Railway Operation Simulator  v2.12.0
A railway simulator for Windows
TrackUnit.cpp
Go to the documentation of this file.
1 // TrackUnit.cpp
2 /*
3  BEWARE OF COMMENTS in .cpp files: they were accurate when written but have
4  sometimes been overtaken by changes and not updated
5  Comments in .h files are believed to be accurate and up to date
6 
7  This is a source code file for "railway.exe", a railway operation
8  simulator, written originally in Borland C++ Builder 4 Professional with
9  later updates in Embarcadero C++Builder 10.2.
10  Copyright (C) 2010 Albert Ball [original development]
11 
12  This program is free software: you can redistribute it and/or modify
13  it under the terms of the GNU General Public License as published by
14  the Free Software Foundation, either version 3 of the License, or
15  (at your option) any later version.
16 
17  This program is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  GNU General Public License for more details.
21 
22  You should have received a copy of the GNU General Public License
23  along with this program. If not, see <http://www.gnu.org/licenses/>.
24 */
25 // ---------------------------------------------------------------------------
26 #include <Classes.hpp>
27 #include <Controls.hpp>
28 #include <StdCtrls.hpp>
29 #include <Forms.hpp>
30 #include <Buttons.hpp>
31 #include <ExtCtrls.hpp>
32 #include <Menus.hpp>
33 #include <Dialogs.hpp>
34 #include <Graphics.hpp>
35 #include <ComCtrls.hpp>
36 #include <fstream>
37 #include <vector>
38 #include <algorithm> //for std::find
39 #include <vcl.h>
40 
41 #pragma hdrstop
42 
43 #include "TrackUnit.h"
44 #include "Utilities.h"
45 // #include "DisplayUnit.h" included in header file
46 #include "GraphicUnit.h"
47 #include "TextUnit.h"
48 #include "TrainUnit.h"
49 
50 #pragma package(smart_init)
51 // ---------------------------------------------------------------------------
52 
55 
56 // ---------------------------------------------------------------------------
57 
58 // FIXED TRACK :-
59 
60 // Constructor to build TrackPieces from array
61 
62 TFixedTrackPiece::TFixedTrackPiece(int SpeedTagVal, TTrackType TrackTypeVal, int LkVal[4], TConfiguration ConfigVal[4], Graphics::TBitmap* GraphicPtrVal,
63  Graphics::TBitmap* SmallGraphicPtrVal) : SpeedTag(SpeedTagVal), TrackType(TrackTypeVal), GraphicPtr(GraphicPtrVal), SmallGraphicPtr(SmallGraphicPtrVal)
64 {
65  for(int x = 0; x < 4; x++)
66  {
67  Link[x] = LkVal[x];
68  Config[x] = ConfigVal[x];
69  }
70 // NamedLocationElements 76, 77, 78, 79, 96, 129, 130, 131, 145 & 146 (platforms, concourses, footcrossings & named non-station locations)
71  FixedNamedLocationElement = false; // underpasses (144 & 145 added at v2.3.1
72  if(SpeedTagVal == 76)
73  {
75  }
76  else if(SpeedTagVal == 77)
77  {
79  }
80  else if(SpeedTagVal == 78)
81  {
83  }
84  else if(SpeedTagVal == 79)
85  {
87  }
88  else if(SpeedTagVal == 96)
89  {
91  }
92  else if(SpeedTagVal == 129)
93  {
95  }
96  else if(SpeedTagVal == 130)
97  {
99  }
100  else if(SpeedTagVal == 131)
101  {
103  }
104  else if(SpeedTagVal == 145)
105  {
107  }
108  else if(SpeedTagVal == 146)
109  {
111  }
112 }
113 
114 // ---------------------------------------------------------------------------
115 
116 TFixedTrackPiece::TFixedTrackPiece() : SpeedTag(0), TrackType(Erase), GraphicPtr(RailGraphics->bmSolidBgnd), SmallGraphicPtr(RailGraphics->smSolidBgnd),
117  FixedNamedLocationElement(false) // default values
118 {
119  for(int x = 0; x < 4; x++)
120  {
121  Link[x] = -1; // -1 & NotSet are the markers for 'unused' respectively
122  Config[x] = NotSet;
123  }
124 }
125 
126 // ---------------------------------------------------------------------------
127 void TFixedTrackPiece::PlotFixedTrackElement(int Caller, int HLocInput, int VLocInput) const
128 {
129  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotFixedTrackElement," + AnsiString(HLocInput) + "," +
130  AnsiString(VLocInput));
131  Display->PlotOutput(33, HLocInput * 16, VLocInput * 16, GraphicPtr);
132  Utilities->CallLogPop(1331);
133 }
134 
135 // ---------------------------------------------------------------------------
136 
137 // VARIABLE TRACK :-
138 
139 // ---------------------------------------------------------------------------
140 
142 {
143  if((this->HLoc == RHElement.HLoc) && (this->VLoc == RHElement.VLoc) && (this->SpeedTag == RHElement.SpeedTag))
144  {
145  return(true);
146  }
147  else
148  {
149  return(false);
150  }
151 }
152 
153 // ---------------------------------------------------------------------------
154 
156 {
157  if((this->HLoc != RHElement.HLoc) || (this->VLoc != RHElement.VLoc) || (this->SpeedTag != RHElement.SpeedTag))
158  {
159  return(true);
160  }
161  else
162  {
163  return(false);
164  }
165 }
166 
167 // ---------------------------------------------------------------------------
168 
170 // 'Variable' in the sense that element might be striped or non-striped
171 {
172  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotVariableTrackElement");
173  Graphics::TBitmap *GraphicOutput = GraphicPtr;
174 
175  if(LocationName == "")
176  {
177  switch(SpeedTag)
178  {
179  case 76: // t platform
180  GraphicOutput = RailGraphics->gl76Striped;
181  break;
182 
183  case 77: // h platform
184  GraphicOutput = RailGraphics->bm77Striped;
185  break;
186 
187  case 78: // v platform
188  GraphicOutput = RailGraphics->bm78Striped;
189  break;
190 
191  case 79: // r platform
192  GraphicOutput = RailGraphics->gl79Striped;
193  break;
194 
195  case 96: // concourse
196  GraphicOutput = RailGraphics->ConcourseStriped;
197  break;
198 
199  case 129: // v footbridge
200  GraphicOutput = RailGraphics->gl129Striped;
201  break;
202 
203  case 130: // h footbridge
204  GraphicOutput = RailGraphics->gl130Striped;
205  break;
206 
207  case 131: // non-station named loc
208  GraphicOutput = RailGraphics->bmNameStriped;
209  break;
210 
211  case 145: // v underpass
212  GraphicOutput = RailGraphics->gl145Striped;
213  break;
214 
215  case 146: // h underpass
216  GraphicOutput = RailGraphics->gl146Striped;
217  break;
218 
219  default:
220  GraphicOutput = GraphicPtr;
221  break;
222  }
223  }
224  Disp->PlotOutput(34, HLoc * 16, VLoc * 16, GraphicOutput);
225  Utilities->CallLogPop(1332);
226 }
227 
228 // ---------------------------------------------------------------------------
229 
230 AnsiString TTrackElement::LogTrack(int Caller) const
231 // for debugging when passes as a call parameter
232 {
233  AnsiString LogString = "TrkEl:-," + AnsiString(ElementID) + "," + LocationName + "," + AnsiString(TrainIDOnElement) + "," +
234  AnsiString(TrainIDOnBridgeTrackPos01) + "," + AnsiString(TrainIDOnBridgeTrackPos23) + ",EndTrkEl,";
235 
236  return(LogString);
237 }
238 
239 // ---------------------------------------------------------------------------
240 
242  TTrackElement::TTrackElement(TFixedTrackPiece Input) : TFixedTrackPiece(Input), HLoc(-2000000000), VLoc(-2000000000), LocationName(""), ActiveTrackElementName(""),
243  Attribute(0), CallingOnSet(false), Length01(Track->DefaultTrackLength), Length23(-1), SpeedLimit01(Track->DefaultTrackSpeedLimit), SpeedLimit23(-1),
244  TrainIDOnElement(-1), TrainIDOnBridgeTrackPos01(-1), TrainIDOnBridgeTrackPos23(-1), StationEntryStopLinkPos1(-1), StationEntryStopLinkPos2(-1),
245  SigAspect(FourAspect)
246  {
247  for(int x = 0; x < 4; x++)
248  {
249  ConnLinkPos[x] = -1;
250  Conn[x] = -1;
251  }
252  if((TrackType == Points) || (TrackType == Crossover) || (TrackType == Bridge))
253  {
256  }
257  }
258 
259 // ---------------------------------------------------------------------------
260 
261 bool TMapComp:: operator()(const THVPair& lower, const THVPair& higher) const // HLoc VLoc
262 {
263  if(lower.second < higher.second)
264  {
265  return(true);
266  }
267  else if(lower.second > higher.second)
268  {
269  return(false);
270  }
271  else if(lower.second == higher.second)
272  {
273  if(lower.first < higher.first)
274  {
275  return(true);
276  }
277  }
278  return(false);
279 }
280 
281 // ---------------------------------------------------------------------------
282 // PrefDirElement Functions
283 // ---------------------------------------------------------------------------
284 
285 TPrefDirElement::TPrefDirElement(TTrackElement ElementIn, int ELinkIn, int ELinkPosIn, int XLinkIn, int XLinkPosIn, int TrackVectorPositionIn)
286  : TTrackElement(ElementIn), ELink(ELinkIn), ELinkPos(ELinkPosIn), XLink(XLinkIn), XLinkPos(XLinkPosIn), TrackVectorPosition(TrackVectorPositionIn),
287  CheckCount(9), IsARoute(false), AutoSignals(false), PrefDirRoute(false)
288 {
289  if(!EntryExitNumber())
290  {
291  throw Exception("EXNumber failure in TPrefDirElement constructor");
292  }
295 }
296 
297 // ---------------------------------------------------------------------------
298 
299 AnsiString TPrefDirElement::LogPrefDir() const
300 // for debugging when passed as a call parameter
301 {
302  AnsiString LogString = "PthEl:-," + AnsiString(ELink) + "," + AnsiString(ELinkPos) + "," + AnsiString(XLink) + "," + AnsiString(XLinkPos) + "," +
303  AnsiString(EXNumber) + "," + AnsiString(TrackVectorPosition) + "," + AnsiString((short)AutoSignals) + "," + AnsiString((short)PrefDirRoute) +
304  ",ElementID," + AnsiString(ElementID) + "," + LocationName + "," + AnsiString(TrainIDOnElement) + "," + AnsiString(TrainIDOnBridgeTrackPos01) + "," +
305  AnsiString(TrainIDOnBridgeTrackPos23);
306 
307 // Track->TrackElementAt(73, TrackVectorPosition).LogTrack(12);
308  return(LogString);
309 }
310 
311 // ---------------------------------------------------------------------------
312 
313 bool TPrefDirElement::EntryExitNumber() // true for valid number
314 /*
315  Computes a number corresponding to ELink & Xlink if set, or to the entry and exit link values for the track
316  at Link[0] and Link[1], or, if ELink or XLink not set, and a complex (4-entry) element, return false for error message.
317  This should be OK because only elements for which ELink & XLink not set are PrefDir/route start elements and leading points
318  as temporary end of PrefDir, and in both cases this function is not called as the direction is not displayed for these elements.
319  Uses simple links between any 2 entry & exit points for use in displaying PrefDir or route graphics, or original graphic during
320  route flashing. Should only be called when ELink & XLink set, or when ELinkPos & XLinkPos set deliberately from a
321  TTrackElement during route setting functions. If a bridge then an additional check is made in case the graphic needed
322  corresponds to an undebridge, i.e a gap needed between entry and exit. In this case the EXNumber is increased by
323  16 so as to be unique. Returns true if valid and sets EXNumber to the selected value.
324 */
325 
326 {
327  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EntryExitNumber");
328  int EXArray[16][2] =
329  {{4, 6}, {2, 8}, // horizontal & vertical
330  {2, 4}, {6, 2}, {8, 6}, {4, 8}, // sharp curves
331  {1, 6}, {3, 8}, {9, 4}, {7, 2}, {1, 8}, {3, 4}, {9, 2}, {7, 6}, // loose curves
332  {1, 9}, {3, 7}}; // forward & reverse diagonals
333 
334  int EXNum = -1;
335  int Entry, Exit;
336 
337  if(ELink > -1)
338  {
339  Entry = ELink; // pick up simple elements even if ELink &/or XLink not set, as no ambiguity
340  }
341  else if(Link[2] == -1)
342  {
343  Entry = Link[0];
344  }
345  else
346  {
347  Utilities->CallLogPop(122);
348  return(false);
349  }
350  if(XLink > -1)
351  {
352  Exit = XLink;
353  }
354  else if(Link[2] == -1)
355  {
356  Exit = Link[1];
357  }
358  else
359  {
360  Utilities->CallLogPop(123);
361  return(false);
362  }
363  for(int x = 0; x < 16; x++)
364  {
365  if(((Entry == EXArray[x][0]) && (Exit == EXArray[x][1])) || ((Entry == EXArray[x][1]) && (Exit == EXArray[x][0]))) //added extra brackets round && segments at v2.9.1
366  {
367  EXNum = x;
368  }
369  }
370  if(EXNum == -1)
371  {
372  Utilities->CallLogPop(124);
373  return(false);
374  }
375  int BrNum = -1;
376 
377 /* The order for bridge entries & exits is as below. Note that there are 3 of each type,
378  the graphic for each of which is different because of the shape of the overbridge. The basic
379  entry/exit value is computed above, and this used to select only from elements with that entry/exit
380  value that is an underbridge, i.e overbridges ignored as the normal graphic is OK for them.
381  int BrEXArray[24][2] = {
382  {4,6},{2,8},{1,9},{3,7},
383  {1,9},{3,7},{1,9},{3,7},
384  {2,8},{4,6},{2,8},{4,6}
385 */
386 
387  if(TrackType == Bridge)
388  {
389  if(EXNum == 1)
390  {
391  if(SpeedTag == 49)
392  {
393  BrNum = 1 + 16;
394  }
395  else if(SpeedTag == 54)
396  {
397  BrNum = 8 + 16;
398  }
399  else if(SpeedTag == 55)
400  {
401  BrNum = 10 + 16;
402  }
403  }
404  else if(EXNum == 0)
405  {
406  if(SpeedTag == 48)
407  {
408  BrNum = 0 + 16;
409  }
410  else if(SpeedTag == 58)
411  {
412  BrNum = 11 + 16;
413  }
414  else if(SpeedTag == 59)
415  {
416  BrNum = 9 + 16;
417  }
418  }
419  else if(EXNum == 14)
420  {
421  if(SpeedTag == 50)
422  {
423  BrNum = 2 + 16;
424  }
425  else if(SpeedTag == 52)
426  {
427  BrNum = 4 + 16;
428  }
429  else if(SpeedTag == 57)
430  {
431  BrNum = 6 + 16;
432  }
433  }
434  else if(EXNum == 15)
435  {
436  if(SpeedTag == 51)
437  {
438  BrNum = 3 + 16;
439  }
440  else if(SpeedTag == 53)
441  {
442  BrNum = 7 + 16;
443  }
444  else if(SpeedTag == 56)
445  {
446  BrNum = 5 + 16;
447  }
448  }
449  }
450  if(BrNum == -1)
451  {
452  EXNumber = EXNum;
453  }
454  else
455  {
456  EXNumber = BrNum;
457  }
458  Utilities->CallLogPop(125);
459  return(true);
460 }
461 
462 // ---------------------------------------------------------------------------
463 
465 /*
466  This is the basic track graphic for use in plotting the original graphic during route flashing.
467  Enter with all set apart from EXGraphic & EntryDirectionGraphic
468 */
469 {
470  if(SpeedTag == 64)
471  {
472  return(RailGraphics->LinkGraphicsPtr[16]); // intercept diagonal buffers
473 
474  }
475  if(SpeedTag == 65)
476  {
477  return(RailGraphics->LinkGraphicsPtr[17]);
478  }
479  if(SpeedTag == 66)
480  {
481  return(RailGraphics->LinkGraphicsPtr[18]);
482  }
483  if(SpeedTag == 67)
484  {
485  return(RailGraphics->LinkGraphicsPtr[19]);
486  }
487  if(SpeedTag == 80)
488  {
489  return(RailGraphics->LinkGraphicsPtr[20]); // intercept continuations
490 
491  }
492  if(SpeedTag == 81)
493  {
494  return(RailGraphics->LinkGraphicsPtr[21]);
495  }
496  if(SpeedTag == 82)
497  {
498  return(RailGraphics->LinkGraphicsPtr[22]);
499  }
500  if(SpeedTag == 83)
501  {
502  return(RailGraphics->LinkGraphicsPtr[23]);
503  }
504  if(SpeedTag == 84)
505  {
506  return(RailGraphics->LinkGraphicsPtr[24]);
507  }
508  if(SpeedTag == 85)
509  {
510  return(RailGraphics->LinkGraphicsPtr[25]);
511  }
512  if(SpeedTag == 86)
513  {
514  return(RailGraphics->LinkGraphicsPtr[26]);
515  }
516  if(SpeedTag == 87)
517  {
518  return(RailGraphics->LinkGraphicsPtr[27]);
519  }
520  if(SpeedTag == 129)
521  {
522  return(RailGraphics->LinkGraphicsPtr[28]); // intercept under footbridges
523 
524  }
525  if(SpeedTag == 130)
526  {
527  return(RailGraphics->LinkGraphicsPtr[29]);
528  }
529  if(XLinkPos == -1) // not set, could be first element or last element = leading point
530  {
531 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or
532 // Points & don't want to display these)
533  if(Link[2] != -1)
534  {
535  return(0); // i.e. complex element, don't display
536  }
537  else
538  {
539  if(!EntryExitNumber())
540  {
541  throw Exception("Error in EntryExitNumber 4");
542  }
543  else
544  {
546  }
547  }
548  }
549  if(EXNumber > 15) // underbridge
550  {
551  return(RailGraphics->BridgeGraphicsPtr[EXNumber - 16]);
552  }
553  else
554  {
556  }
557 }
558 
559 // ---------------------------------------------------------------------------
560 
562 /*
563  As above but for PrefDir graphics.
564 */
565 {
566  if(SpeedTag == 64)
567  {
568  return(RailGraphics->LinkPrefDirGraphicsPtr[16]); // intercept diagonal buffers
569 
570  }
571  if(SpeedTag == 65)
572  {
574  }
575  if(SpeedTag == 66)
576  {
578  }
579  if(SpeedTag == 67)
580  {
582  }
583  if(SpeedTag == 80)
584  {
585  return(RailGraphics->LinkPrefDirGraphicsPtr[20]); // intercept continuations
586 
587  }
588  if(SpeedTag == 81)
589  {
591  }
592  if(SpeedTag == 82)
593  {
595  }
596  if(SpeedTag == 83)
597  {
599  }
600  if(SpeedTag == 84)
601  {
603  }
604  if(SpeedTag == 85)
605  {
607  }
608  if(SpeedTag == 86)
609  {
611  }
612  if(SpeedTag == 87)
613  {
615  }
616  if(SpeedTag == 129)
617  {
618  return(RailGraphics->LinkPrefDirGraphicsPtr[28]); // intercept under footbridges
619 
620  }
621  if(SpeedTag == 130)
622  {
624  }
625  if(XLinkPos == -1) // not set, could be first element or last element = leading point
626  {
627 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
628  if(Link[2] != -1)
629  {
630  return(0); // i.e. complex element, don't display
631  }
632  else
633  {
634  if(!EntryExitNumber())
635  {
636  throw Exception("Error in EntryExitNumber 5");
637  }
638  else
639  {
641  }
642  }
643  }
644  if(EXNumber > 15) // underbridge
645  {
647  }
648  else
649  {
651  }
652 }
653 
654 // ---------------------------------------------------------------------------
655 
656 Graphics::TBitmap *TPrefDirElement::GetRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute)
657 /*
658  As above but for route graphics.
659 */
660 {
661  if(!AutoSigsFlag && !PrefDirRoute)
662  {
663  if(SpeedTag == 64)
664  {
665  return(RailGraphics->LinkNonSigRouteGraphicsPtr[16]); // intercept diagonal buffers
666 
667  }
668  if(SpeedTag == 65)
669  {
671  }
672  if(SpeedTag == 66)
673  {
675  }
676  if(SpeedTag == 67)
677  {
679  }
680  if(SpeedTag == 80)
681  {
682  return(RailGraphics->LinkNonSigRouteGraphicsPtr[20]); // intercept continuations
683 
684  }
685  if(SpeedTag == 81)
686  {
688  }
689  if(SpeedTag == 82)
690  {
692  }
693  if(SpeedTag == 83)
694  {
696  }
697  if(SpeedTag == 84)
698  {
700  }
701  if(SpeedTag == 85)
702  {
704  }
705  if(SpeedTag == 86)
706  {
708  }
709  if(SpeedTag == 87)
710  {
712  }
713  if(SpeedTag == 129)
714  {
715  return(RailGraphics->LinkNonSigRouteGraphicsPtr[28]); // intercept under footbridges
716 
717  }
718  if(SpeedTag == 130)
719  {
721  }
722  if(XLinkPos == -1) // not set, could be first element or last element = leading point
723  {
724  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
725  if(Link[2] != -1)
726  {
727  return(0); // i.e. complex element, don't display
728  }
729  else
730  {
731  if(!EntryExitNumber())
732  {
733  throw Exception("Error in EntryExitNumber 6");
734  }
735  else
736  {
738  }
739  }
740  }
741  if(EXNumber > 15) // underbridge
742  {
744  }
745  else
746  {
748  }
749  }
750 
751  else if(!AutoSigsFlag && PrefDirRoute)
752  {
753  if(SpeedTag == 64)
754  {
755  return(RailGraphics->LinkSigRouteGraphicsPtr[16]); // intercept diagonal buffers
756 
757  }
758  if(SpeedTag == 65)
759  {
761  }
762  if(SpeedTag == 66)
763  {
765  }
766  if(SpeedTag == 67)
767  {
769  }
770  if(SpeedTag == 80)
771  {
772  return(RailGraphics->LinkSigRouteGraphicsPtr[20]); // intercept continuations
773 
774  }
775  if(SpeedTag == 81)
776  {
778  }
779  if(SpeedTag == 82)
780  {
782  }
783  if(SpeedTag == 83)
784  {
786  }
787  if(SpeedTag == 84)
788  {
790  }
791  if(SpeedTag == 85)
792  {
794  }
795  if(SpeedTag == 86)
796  {
798  }
799  if(SpeedTag == 87)
800  {
802  }
803  if(SpeedTag == 129)
804  {
805  return(RailGraphics->LinkSigRouteGraphicsPtr[28]); // intercept under footbridges
806 
807  }
808  if(SpeedTag == 130)
809  {
811  }
812  if(XLinkPos == -1) // not set, could be first element or last element = leading point
813  {
814  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
815  if(Link[2] != -1)
816  {
817  return(0); // i.e. complex element, don't display
818  }
819  else
820  {
821  if(!EntryExitNumber())
822  {
823  throw Exception("Error in EntryExitNumber 10");
824  }
825  else
826  {
828  }
829  }
830  }
831  if(EXNumber > 15) // underbridge
832  {
834  }
835  else
836  {
838  }
839  }
840 
841  else
842  {
843  if(SpeedTag == 64)
844  {
845  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]); // intercept diagonal buffers
846 
847  }
848  if(SpeedTag == 65)
849  {
851  }
852  if(SpeedTag == 66)
853  {
855  }
856  if(SpeedTag == 67)
857  {
859  }
860  if(SpeedTag == 80)
861  {
862  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]); // intercept continuations
863 
864  }
865  if(SpeedTag == 81)
866  {
868  }
869  if(SpeedTag == 82)
870  {
872  }
873  if(SpeedTag == 83)
874  {
876  }
877  if(SpeedTag == 84)
878  {
880  }
881  if(SpeedTag == 85)
882  {
884  }
885  if(SpeedTag == 86)
886  {
888  }
889  if(SpeedTag == 87)
890  {
892  }
893  if(SpeedTag == 129)
894  {
895  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]); // intercept under footbridges
896 
897  }
898  if(SpeedTag == 130)
899  {
901  }
902  if(XLinkPos == -1) // not set, could be first element or last element = leading point
903  {
904  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
905  if(Link[2] != -1)
906  {
907  return(0); // i.e. complex element, don't display
908  }
909  else
910  {
911  if(!EntryExitNumber())
912  {
913  throw Exception("Error in EntryExitNumber 11");
914  }
915  else
916  {
918  }
919  }
920  }
921  if(EXNumber > 15) // underbridge
922  {
924  }
925  else
926  {
928  }
929  }
930 }
931 
932 // ---------------------------------------------------------------------------
933 
935 /*
936  As above but for route flashing graphics. (Disused - now combined with above)
937 */
938 {
939  if(SpeedTag == 64)
940  {
941  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]); // intercept diagonal buffers
942 
943  }
944  if(SpeedTag == 65)
945  {
947  }
948  if(SpeedTag == 66)
949  {
951  }
952  if(SpeedTag == 67)
953  {
955  }
956  if(SpeedTag == 80)
957  {
958  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]); // intercept continuations
959 
960  }
961  if(SpeedTag == 81)
962  {
964  }
965  if(SpeedTag == 82)
966  {
968  }
969  if(SpeedTag == 83)
970  {
972  }
973  if(SpeedTag == 84)
974  {
976  }
977  if(SpeedTag == 85)
978  {
980  }
981  if(SpeedTag == 86)
982  {
984  }
985  if(SpeedTag == 87)
986  {
988  }
989  if(SpeedTag == 129)
990  {
991  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]); // intercept under footbridges
992 
993  }
994  if(SpeedTag == 130)
995  {
997  }
998  if(XLinkPos == -1) // not set, could be first element or last element = leading point
999  {
1000 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
1001  if(Link[2] != -1)
1002  {
1003  return(0); // i.e. complex element, don't display
1004  }
1005  else
1006  {
1007  if(!EntryExitNumber())
1008  {
1009  throw Exception("Error in EntryExitNumber 7");
1010  }
1011  else
1012  {
1014  }
1015  }
1016  }
1017  if(EXNumber > 15) // underbridge
1018  {
1020  }
1021  else
1022  {
1024  }
1025 }
1026 
1027 // ---------------------------------------------------------------------------
1028 
1030 /*
1031  Get PrefDir direction graphic. Enter with all set apart from EXGraphic & EntryDirectionGraphic
1032 */
1033 {
1034  if((ELink > 0) && (ELink < 10) && (ELink != 5))
1035  {
1037  }
1038  else
1039  {
1040  throw Exception("Error in EntryExitNumber 8");
1041  }
1042 }
1043 
1044 // ---------------------------------------------------------------------------
1045 
1046 Graphics::TBitmap *TPrefDirElement::GetDirectionRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute) const
1047 /*
1048  Get route direction graphic. Enter with all set apart from EXGraphic & EntryDirectionGraphic
1049 */
1050 {
1051  if((ELink > 0) && (ELink < 10) && (ELink != 5))
1052  {
1053  if(!AutoSigsFlag && !PrefDirRoute)
1054  {
1056  }
1057  else if(!AutoSigsFlag && PrefDirRoute)
1058  {
1060  }
1061  else
1062  {
1064  }
1065  }
1066  else
1067  {
1068  throw Exception("Error in EntryExitNumber 9");
1069  }
1070 }
1071 
1072 // ---------------------------------------------------------------------------
1073 
1075 /*
1076  Set == operator when TrackVectorPosition, ELink & XLink all same
1077 */
1078 {
1079  if((this->TrackVectorPosition == RHElement.TrackVectorPosition) && (this->ELink == RHElement.ELink) && (this->XLink == RHElement.XLink))
1080  {
1081  return(true);
1082  }
1083  else
1084  {
1085  return(false);
1086  }
1087 }
1088 
1089 // ---------------------------------------------------------------------------
1090 
1092 /*
1093  Set != operator when any of TrackVectorPosition, ELink or XLink different
1094 */
1095 {
1096  if((this->TrackVectorPosition == RHElement.TrackVectorPosition) && (this->ELink == RHElement.ELink) && (this->XLink == RHElement.XLink))
1097  {
1098  return(false);
1099  }
1100  else
1101  {
1102  return(true);
1103  }
1104 }
1105 
1106 // ---------------------------------------------------------------------------
1107 // Track functions
1108 // ---------------------------------------------------------------------------
1109 
1110 // ---------------------------------------------------------------------------
1111 
1112 TTrack::TActiveLevelCrossing::TActiveLevelCrossing()
1113 {
1114  TypeOfRoute = 0;
1115  ReducedTimePenalty = false;
1116  BarrierState = Up;
1117  ChangeDuration = 0.0;
1118  BaseElementSpeedTag = 1;
1119  HLoc = 0;
1120  VLoc = 0;
1121  StartTime = TDateTime(0);
1122 }
1123 
1124 // ---------------------------------------------------------------------------
1125 
1127 {
1128 // CurrentSpeedButtonTag = 0; //not assigned yet
1129 
1130  HLocMin = 2000000000;
1131  VLocMin = 2000000000;
1132  HLocMax = -2000000000;
1133  VLocMax = -2000000000;
1134  SkipLocationNameMultiMapCheck = false; // new at v2.2.0, false is default value
1135  CopyFlag = false; // only true for copying, so names aren't copied
1136  AnsiString NL = '\n';
1137 
1138  RouteFailMessage = "Unable to set a route:" + NL + NL + "it may be unreachable; " + NL + NL +
1139  "reachable but with too many different directions leading away from the start point - set some points on the route required; " + NL + NL +
1140  "blocked by a train, another route or a changing level crossing; " + NL + NL +
1141  "or invalid - possibly due to a preferred direction mismatch, or a missed signal in a blue route or green route restricted to consecutive signals.";
1142 
1147 
1148  int InternalLinkCheckArray[9][2] =
1149  {{1, 9}, {4, 6}, {7, 3}, {2, 8}, {0, 0}, {8, 2}, {3, 7}, {6, 4}, {9, 1}};
1150 
1151 /* array of valid link values for 'old' location and 'new' location, where
1152  array number = (((Hnew - Hold)+1)*3) + ((Vnew - Vold)+1) */
1153 
1154  for(int x = 0; x < 9; x++)
1155  {
1156  for(int y = 0; y < 2; y++)
1157  {
1158  LinkCheckArray[x][y] = InternalLinkCheckArray[x][y];
1159  }
1160  }
1161 
1162 // Platform and default track element values
1163  TopPlatAllowed << 1 << 9 << 10 << 30 << 31 << 60 << 61 << 68 << 69 << 77 << 125 << 126 << 129 << 145;
1164 // top & bot sigs, straights, straight points, buffers, signal, vert footcrossing, bot plat
1165  BotPlatAllowed << 1 << 7 << 8 << 28 << 29 << 60 << 61 << 68 << 69 << 76 << 125 << 126 << 129 << 145;
1166  LeftPlatAllowed << 2 << 12 << 14 << 33 << 35 << 62 << 63 << 70 << 71 << 79 << 127 << 128 << 130 << 146;
1167  RightPlatAllowed << 2 << 11 << 13 << 32 << 34 << 62 << 63 << 70 << 71 << 78 << 127 << 128 << 130 << 146;
1168  NameAllowed << 1 << 2 << 3 << 4 << 5 << 6 << 20 << 21 << 22 << 23 << 24 << 25 << 26 << 27 // disallow diagonals, points, crossovers, bridges, gaps,
1169  << 60 << 61 << 62 << 63 << 68 << 69 << 70 << 71 << 80 << 81 << 82 << 83 << 125 << 126 << 127 << 128; // diag continuations, diag buffers, footcrossings (diagonals may be OK
1170  // but as can't link diagonal locations would need solid blocks to allow linkage & that would look untidy except for single
1171  // elements, & can always use straights so leave out.) Allow horiz & vert signals as from v2.6.0
1172  LevelCrossingAllowed << 1 << 2; // only allow on straight tracks without direction markers
1173 // Note platforms not allowed at continuations, but named non-station locations OK, though not allowed in timetables
1174 
1175  int HVArray[10][2] =
1176  {{0, 0}, {-1, -1}, {0, -1}, {1, -1}, {-1, 0}, {0, 0}, {1, 0}, {-1, 1}, {0, 1}, {1, 1}};
1177 
1178  for(int x = 0; x < 10; x++)
1179  {
1180  for(int y = 0; y < 2; y++)
1181  {
1182  LinkHVArray[x][y] = HVArray[x][y];
1183  }
1184  }
1185  TrackFinished = false;
1186 // DistancesSet = false;
1187 
1188  TSigElement TempSigTable[40] = // original four aspect
1189  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1190  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1191 
1192  {68, 1, RailGraphics->bm68yellow}, {69, 1, RailGraphics->bm69yellow}, {70, 1, RailGraphics->bm70yellow}, {71, 1, RailGraphics->bm71yellow},
1193  {72, 1, RailGraphics->bm72yellow}, {73, 1, RailGraphics->bm73yellow}, {74, 1, RailGraphics->bm74yellow}, {75, 1, RailGraphics->bm75yellow},
1194 
1197 
1198  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1199  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1200 
1201  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1202  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1203  {75, 4, RailGraphics->gl75}};
1204 
1205  for(int x = 0; x < 40; x++)
1206  {
1207  SigTable[x] = TempSigTable[x];
1208  }
1209 
1210  TSigElement TempSigTableThreeAspect[40] =
1211  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1212  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1213 
1214  {68, 1, RailGraphics->bm68yellow}, {69, 1, RailGraphics->bm69yellow}, {70, 1, RailGraphics->bm70yellow}, {71, 1, RailGraphics->bm71yellow},
1215  {72, 1, RailGraphics->bm72yellow}, {73, 1, RailGraphics->bm73yellow}, {74, 1, RailGraphics->bm74yellow}, {75, 1, RailGraphics->bm75yellow},
1216 
1217  {68, 2, RailGraphics->bm68green}, {69, 2, RailGraphics->bm69green}, {70, 2, RailGraphics->bm70green}, {71, 2, RailGraphics->bm71green},
1218  {72, 2, RailGraphics->bm72green}, {73, 2, RailGraphics->bm73green}, {74, 2, RailGraphics->bm74green}, {75, 2, RailGraphics->bm75green},
1219 
1220  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1221  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1222 
1223  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1224  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1225  {75, 4, RailGraphics->gl75}};
1226 
1227  for(int x = 0; x < 40; x++)
1228  {
1229  SigTableThreeAspect[x] = TempSigTableThreeAspect[x];
1230  }
1231 
1232  TSigElement TempSigTableTwoAspect[40] =
1233  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1234  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1235 
1236  {68, 1, RailGraphics->bm68green}, {69, 1, RailGraphics->bm69green}, {70, 1, RailGraphics->bm70green}, {71, 1, RailGraphics->bm71green},
1237  {72, 1, RailGraphics->bm72green}, {73, 1, RailGraphics->bm73green}, {74, 1, RailGraphics->bm74green}, {75, 1, RailGraphics->bm75green},
1238 
1239  {68, 2, RailGraphics->bm68green}, {69, 2, RailGraphics->bm69green}, {70, 2, RailGraphics->bm70green}, {71, 2, RailGraphics->bm71green},
1240  {72, 2, RailGraphics->bm72green}, {73, 2, RailGraphics->bm73green}, {74, 2, RailGraphics->bm74green}, {75, 2, RailGraphics->bm75green},
1241 
1242  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1243  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1244 
1245  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1246  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1247  {75, 4, RailGraphics->gl75}};
1248 
1249  for(int x = 0; x < 40; x++)
1250  {
1251  SigTableTwoAspect[x] = TempSigTableTwoAspect[x];
1252  }
1253 
1254  TSigElement TempSigTableGroundSignal[40] =
1258 
1262 
1266 
1270 
1271  {68, 4, RailGraphics->bm68grounddblred}, {69, 4, RailGraphics->bm69grounddblred}, // Attr 4 disused but leave in case re-instate
1274 
1275  for(int x = 0; x < 40; x++)
1276  {
1277  SigTableGroundSignal[x] = TempSigTableGroundSignal[x];
1278  }
1279 
1280 /*
1281  Named Location Arrays: Set out the adjacent positions and tracktypes that are accepted as valid connections for
1282  a single location. These are as follows:-
1283  Directly Adjacent = up, down, left or right - NOT diagonal.
1284  There are two separate groups, platforms, concourses & footcrossings (providing the crossing part touches or overlaps the other relevant
1285  named location) all link with each other providing directly adjacent, but not to NamedNonStationLocations.
1286  NamedNonStationLocation link to other NamedNonStationLocations providing directly adjacent, but not to anything else.
1287 
1288  //t 76
1289  //b 77
1290  //l 78
1291  //r 79
1292  //c 96
1293  //v fb 129
1294  //h fb 130
1295  //v underpass 145
1296  //h underpass 146
1297  //n 131
1298 */
1299 
1300  int Tag76[25][3] =
1301  {{-1, 0, 96}, // c top plat
1302  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1303  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1304  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {0, 0, 77}, {-1, 0, 78}, // l
1305  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1306  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, -1, 129}, // v fb
1307  {0, 0, 129}, {0, -1, 145}, // v up
1308  {0, 0, 145}};
1309 
1310  for(int x = 0; x < 25; x++)
1311  {
1312  for(int y = 0; y < 3; y++)
1313  {
1314  Tag76Array[x][y] = Tag76[x][y];
1315  }
1316  }
1317 
1318  int Tag77[25][3] =
1319  {{-1, 0, 96}, // c bot plat
1320  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1321  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {0, 0, 76}, {-1, 0, 77}, // b
1322  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1323  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1324  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 1, 129}, // v fb
1325  {0, 0, 129}, {0, 1, 145}, // v up
1326  {0, 0, 145}};
1327 
1328  for(int x = 0; x < 25; x++)
1329  {
1330  for(int y = 0; y < 3; y++)
1331  {
1332  Tag77Array[x][y] = Tag77[x][y];
1333  }
1334  }
1335 
1336  int Tag78[25][3] =
1337  {{-1, 0, 96}, // c left plat
1338  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1339  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1340  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1341  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1342  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 0, 79}, {-1, 0, 130}, // h fb
1343  {0, 0, 130}, {-1, 0, 146}, // h up
1344  {0, 0, 146}};
1345 
1346  for(int x = 0; x < 25; x++)
1347  {
1348  for(int y = 0; y < 3; y++)
1349  {
1350  Tag78Array[x][y] = Tag78[x][y];
1351  }
1352  }
1353 
1354  int Tag79[25][3] =
1355  {{-1, 0, 96}, // c right plat
1356  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1357  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1358  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1359  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {0, 0, 78}, {-1, 0, 79}, // r
1360  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {1, 0, 130}, // h fb
1361  {0, 0, 130}, {1, 0, 146}, // h up
1362  {0, 0, 146}};
1363 
1364  for(int x = 0; x < 25; x++)
1365  {
1366  for(int y = 0; y < 3; y++)
1367  {
1368  Tag79Array[x][y] = Tag79[x][y];
1369  }
1370  }
1371 
1372  int Tag96[28][3] =
1373  {{-1, 0, 96}, // c //concourse
1374  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1375  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1376  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1377  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1378  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 1, 129}, // v fb
1379  {0, -1, 129}, {1, 0, 130}, // h fb
1380  {-1, 0, 130}, {0, 1, 145}, // v up
1381  {0, -1, 145}, {1, 0, 146}, // h up
1382  {-1, 0, 146}};
1383 
1384  for(int x = 0; x < 28; x++)
1385  {
1386  for(int y = 0; y < 3; y++)
1387  {
1388  Tag96Array[x][y] = Tag96[x][y];
1389  }
1390  }
1391 
1392  int Tag129[8][3] = // vert fb
1393  {{0, -1, 96}, // c
1394  {0, -1, 77}, // b
1395  {0, -1, 129}, // v fb
1396 
1397  {0, 1, 96}, // c
1398  {0, 1, 76}, // t
1399  {0, 1, 129}, // v fb
1400 
1401  {0, 0, 76}, // t
1402  {0, 0, 77}}; // b
1403 
1404  for(int x = 0; x < 8; x++)
1405  {
1406  for(int y = 0; y < 3; y++)
1407  {
1408  Tag129Array[x][y] = Tag129[x][y];
1409  }
1410  }
1411 
1412  int Tag145[8][3] = // vert up
1413  {{0, -1, 96}, // c
1414  {0, -1, 77}, // b
1415  {0, -1, 145}, // v fb
1416 
1417  {0, 1, 96}, // c
1418  {0, 1, 76}, // t
1419  {0, 1, 145}, // v fb
1420 
1421  {0, 0, 76}, // t
1422  {0, 0, 77}}; // b
1423 
1424  for(int x = 0; x < 8; x++)
1425  {
1426  for(int y = 0; y < 3; y++)
1427  {
1428  Tag145Array[x][y] = Tag145[x][y];
1429  }
1430  }
1431 
1432  int Tag130[8][3] = // hor fb
1433  {{-1, 0, 96}, // c
1434  {-1, 0, 79}, // r
1435  {-1, 0, 130}, // h fb
1436 
1437  {1, 0, 96}, // c
1438  {1, 0, 78}, // l
1439  {1, 0, 130}, // h fb
1440 
1441  {0, 0, 78}, // l
1442  {0, 0, 79}}; // r
1443 
1444  for(int x = 0; x < 8; x++)
1445  {
1446  for(int y = 0; y < 3; y++)
1447  {
1448  Tag130Array[x][y] = Tag130[x][y];
1449  }
1450  }
1451 
1452  int Tag146[8][3] = // hor up
1453  {{-1, 0, 96}, // c
1454  {-1, 0, 79}, // r
1455  {-1, 0, 146}, // h fb
1456 
1457  {1, 0, 96}, // c
1458  {1, 0, 78}, // l
1459  {1, 0, 146}, // h fb
1460 
1461  {0, 0, 78}, // l
1462  {0, 0, 79}}; // r
1463 
1464  for(int x = 0; x < 8; x++)
1465  {
1466  for(int y = 0; y < 3; y++)
1467  {
1468  Tag146Array[x][y] = Tag146[x][y];
1469  }
1470  }
1471 
1472  int Tag131[4][3] =
1473  {{-1, 0, 131}, // n
1474  {1, 0, 131}, {0, -1, 131}, {0, 1, 131}};
1475 
1476  for(int x = 0; x < 4; x++)
1477  {
1478  for(int y = 0; y < 3; y++)
1479  {
1480  Tag131Array[x][y] = Tag131[x][y];
1481  }
1482  }
1483 
1484  int InternalFlipArray[FirstUnusedSpeedTagNumber] =
1485  {
1486  0, 1, 2, 5, 6, 3, 4, 9, 10, 7, 8, 13, 14, 11, 12, 15, 16, 17, 19, 18, 22, 23, 20, 21, 26, 27, 24, 25, 30, 31, 28, 29, 34, 35, 32, 33, 38, 39, 36, 37, 42,
1487  43, 40, 41, 45, 44, 47, 46, 48, 49, 51, 50, 53, 52, 55, 54, 57, 56, 59, 58, 60, 61, 63, 62, 66, 67, 64, 65, 68, 69, 71, 70, 74, 75, 72, 73, 77, 76, 78,
1488  79, 80, 81, 83, 82, 86, 87, 84, 85, 88, 89, 91, 90, 94, 95, 92, 93, 96, 99, 100, 97, 98, 103, 104, 101, 102, 106, 105, 109, 110, 107, 108, 113, 114,
1489  111, 112, 117, 118, 115, 116, 119, 120, 121, 123, 122, 124, 125, 126, 128, 127, 129, 130, 131, 134, 133, 132, 135, 139, 138, 137, 136, 143, 142, 141,
1490  140, 144, 145, 146
1491  };
1492 
1493  int InternalMirrorArray[FirstUnusedSpeedTagNumber] =
1494  {
1495  0, 1, 2, 4, 3, 6, 5, 8, 7, 10, 9, 12, 11, 14, 13, 15, 16, 17, 19, 18, 21, 20, 23, 22, 25, 24, 27, 26, 29, 28, 31, 30, 33, 32, 35, 34, 37, 36, 39, 38, 41,
1496  40, 43, 42, 45, 44, 47, 46, 48, 49, 51, 50, 53, 52, 55, 54, 57, 56, 59, 58, 61, 60, 62, 63, 65, 64, 67, 66, 69, 68, 70, 71, 73, 72, 75, 74, 76, 77, 79,
1497  78, 81, 80, 82, 83, 85, 84, 87, 86, 89, 88, 90, 91, 93, 92, 95, 94, 96, 98, 97, 100, 99, 102, 101, 104, 103, 106, 105, 108, 107, 110, 109, 112, 111,
1498  114, 113, 116, 115, 118, 117, 119, 120, 124, 122, 123, 121, 126, 125, 127, 128, 129, 130, 131, 132, 135, 134, 133, 137, 136, 139, 138, 142, 143, 140,
1499  141, 144, 145, 146
1500  };
1501 
1502  int InternalRotRightArray[FirstUnusedSpeedTagNumber] =
1503  {
1504  0, 2, 1, 4, 6, 3, 5, 14, 12, 13, 11, 7, 9, 8, 10, 15, 16, 17, 19, 18, 25, 27, 24, 26, 21, 23, 20, 22, 35, 33, 34, 32, 28, 30, 29, 31, 41, 43, 40, 42, 37,
1505  39, 36, 38, 46, 47, 44, 45, 49, 48, 51, 50, 56, 57, 58, 59, 52, 53, 54, 55, 63, 62, 60, 61, 65, 67, 64, 66, 71, 70, 68, 69, 73, 75, 72, 74, 79, 78, 76,
1506  77, 83, 82, 80, 81, 85, 87, 84, 86, 91, 90, 88, 89, 93, 95, 92, 94, 96, 102, 104, 101, 103, 98, 100, 97, 99, 106, 105, 108, 110, 107, 109, 116, 118,
1507  115, 117, 112, 114, 111, 113, 120, 119, 122, 124, 121, 123, 127, 128, 126, 125, 130, 129, 131, 133, 134, 135, 132, 137, 138, 139, 136, 143, 142, 140,
1508  141, 144, 146, 145
1509  };
1510 
1511  int InternalRotLeftArray[FirstUnusedSpeedTagNumber] =
1512  {
1513  0, 2, 1, 5, 3, 6, 4, 11, 13, 12, 14, 10, 8, 9, 7, 15, 16, 17, 19, 18, 26, 24, 27, 25, 22, 20, 23, 21, 32, 34, 33, 35, 31, 29, 30, 28, 42, 40, 43, 41, 38,
1514  36, 39, 37, 46, 47, 44, 45, 49, 48, 51, 50, 56, 57, 58, 59, 52, 53, 54, 55, 62, 63, 61, 60, 66, 64, 67, 65, 70, 71, 69, 68, 74, 72, 75, 73, 78, 79, 77,
1515  76, 82, 83, 81, 80, 86, 84, 87, 85, 90, 91, 89, 88, 94, 92, 95, 93, 96, 103, 101, 104, 102, 99, 97, 100, 98, 106, 105, 109, 107, 110, 108, 117, 115,
1516  118, 116, 113, 111, 114, 112, 120, 119, 123, 121, 124, 122, 128, 127, 125, 126, 130, 129, 131, 135, 132, 133, 134, 139, 136, 137, 138, 142, 143, 141,
1517  140, 144, 146, 145
1518  };
1519 
1520  for(int x = 0; x < FirstUnusedSpeedTagNumber; x++)
1521  {
1522  FlipArray[x] = InternalFlipArray[x];
1523  MirrorArray[x] = InternalMirrorArray[x];
1524  RotRightArray[x] = InternalRotRightArray[x];
1525  RotLeftArray[x] = InternalRotLeftArray[x];
1526  }
1527 }
1528 
1529 // ---------------------------------------------------------------------------
1531 {
1532 // delete TrackVectorPtr;
1533 // delete FixedTrackArrayPtr;
1534  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.begin();
1535 
1536  while(UGMIt != Track->UserGraphicMap.end()) // delete all the TPictures in the map
1537  {
1538  delete UGMIt->second;
1539  UGMIt++;
1540  }
1541  delete GapFlashGreen;
1542  delete GapFlashRed;
1543  // all the rest are cleared by the relevant automatic destructors
1544 }
1545 
1546 // ---------------------------------------------------------------------------
1547 
1549 {
1550  Graphics::TBitmap *TrackImageArray[FirstUnusedSpeedTagNumber] =
1551  {
1552 // loc 0 not used, set to bmSolidBgnd
1556 // no 17 not used (was used for text in early phases), set to bmSolidBgnd
1576  };
1577 
1578  Graphics::TBitmap *SmallTrackImageArray[FirstUnusedSpeedTagNumber] =
1579  {
1580 // loc 0 not used, set to smSolidBgnd
1584 // no 17 not used (was used for text in early phases), set to smSolidBgnd
1603  RailGraphics->smLC, RailGraphics->sm129, RailGraphics->sm130 // use small footbridges for underpasses
1604  };
1605 
1606 // track types
1607  TTrackType TrackTypeArray[FirstUnusedSpeedTagNumber] =
1608  {
1609  Erase, // 1 0
1610  Simple, Simple, Simple, Simple, Simple, Simple, // 6 1-6
1611  Points, Points, Points, Points, Points, Points, Points, Points, // 8 7-14
1612  Crossover, Crossover, // 2 15-16
1613  Unused, // 17 (was for text in earlier development) //1 17
1616  Crossover, Crossover, Crossover, Crossover, // 4 44-47
1620  Platform, Platform, Platform, Platform, // 4 76-79
1623  Concourse, // 1 96
1626  Simple, Simple, Simple, Simple, // 4 125-128
1627  FootCrossing, FootCrossing, // 2 129-130
1628  NamedNonStationLocation, // 1 131
1629  Points, Points, Points, Points, Points, Points, Points, Points, // 8 132-139
1630  Simple, Simple, Simple, Simple, // 4 140-143
1631  LevelCrossing, // 1 144
1632  FootCrossing, FootCrossing // 2 145 & 146
1633  };
1634 
1635 // links
1636  int Links[FirstUnusedSpeedTagNumber][4] =
1637  {{-1, -1, -1, -1}, // erase element
1638  {4, 6, -1, -1}, {2, 8, -1, -1}, {6, 8, -1, -1}, {4, 8, -1, -1}, {2, 6, -1, -1}, {2, 4, -1, -1}, // simple
1639  {4, 6, 4, 2}, {6, 4, 6, 2}, {4, 6, 4, 8}, {6, 4, 6, 8}, {8, 2, 8, 4}, {8, 2, 8, 6}, {2, 8, 2, 4}, {2, 8, 2, 6}, // points
1640 // points always have links 0 & 2 = lead, link 1 = trailing straight, link 3 = trailing diverging
1641  {4, 6, 2, 8}, {1, 9, 3, 7}, // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
1642  {-1, -1, -1, -1}, // unused
1643  {3, 7, -1, -1}, {1, 9, -1, -1}, {7, 6, -1, -1}, {4, 9, -1, -1}, {1, 6, -1, -1}, {4, 3, -1, -1}, {3, 8, -1, -1}, {1, 8, -1, -1}, {2, 9, -1, -1},
1644  {2, 7, -1, -1}, // simple
1645  {4, 6, 4, 3}, {6, 4, 6, 1}, {4, 6, 4, 9}, {6, 4, 6, 7}, {8, 2, 8, 1}, {8, 2, 8, 3}, {2, 8, 2, 7}, {2, 8, 2, 9}, {9, 1, 9, 2}, {7, 3, 7, 2}, {3, 7, 3, 8}, {1, 9, 1, 8}, {9, 1, 9, 4}, {7, 3, 7, 6}, {3, 7, 3, 4}, {1, 9, 1, 6}, // points
1646 // points always have links 0 & 2 = lead, link 1 = trailing straight (or left diverging if no straight), link 3 = trailing diverging
1647 // (or right diverging if no straight)
1648  {1, 9, 2, 8}, {2, 8, 3, 7}, {4, 6, 3, 7}, {1, 9, 4, 6}, // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
1649  {2, 8, 4, 6}, {4, 6, 2, 8}, {3, 7, 1, 9}, {1, 9, 3, 7}, {2, 8, 1, 9}, {2, 8, 3, 7}, {3, 7, 2, 8}, {1, 9, 2, 8}, {4, 6, 3, 7}, {4, 6, 1, 9}, {1, 9, 4, 6}, {3, 7, 4, 6}, // bridge, links 2 & 3 = underbridge
1650  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // buffers - position 0 = buffer
1651  {4, 6, -1, -1}, {4, 6, -1, -1}, {2, 8, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {3, 7, -1, -1}, {1, 9, -1, -1}, // signals (need Config to determine signal end, see below)
1652  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, // platform
1653  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // continuation - position 0 = continuation
1654  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // gapjump - position 0 = gap
1655  {-1, -1, -1, -1}, // Concourse
1656  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1657  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1658  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1659  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, // Parapets
1660  {4, 6, -1, -1}, {4, 6, -1, -1}, {2, 8, -1, -1}, {2, 8, -1, -1}, // arrows
1661  {4, 6, -1, -1}, {2, 8, -1, -1}, // footbridges
1662  {-1, -1, -1, -1}, // NamedNonStationLocation
1663  {8, 1, 8, 3}, {4, 3, 4, 9}, {2, 9, 2, 7}, {6, 7, 6, 1}, {9, 4, 9, 2}, {7, 2, 7, 6}, {1, 6, 1, 8}, {3, 8, 3, 4}, // points without straight legs
1664 // these points have links 0 & 2 = lead, link 1 = LH trailing, link 3 = RH trailing
1665  {3, 7, -1, -1}, {3, 7, -1, -1}, {1, 9, -1, -1}, {1, 9, -1, -1}, // arrowed diagonals
1666  {-1, -1, -1, -1}, // level crossing
1667  {4, 6, -1, -1}, {2, 8, -1, -1}, // underpasses/surface crossings
1668  };
1669 
1671  {{NotSet, NotSet, NotSet, NotSet}, // unused
1675  {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, // points
1677  {NotSet, NotSet, NotSet, NotSet}, // unused
1681  {Connection, Connection, NotSet, NotSet}, // simple
1685  {Lead, Trail, Lead, Trail}, // points
1687  {CrossConn, CrossConn, CrossConn, CrossConn}, // crossover
1695  {Signal, Connection, NotSet, NotSet}, {Signal, Connection, NotSet, NotSet}, {Connection, Signal, NotSet, NotSet}, {Connection, Signal, NotSet, NotSet}, // signals (signal at exit end in forward direction)
1701  {NotSet, NotSet, NotSet, NotSet}, // Concourse
1710  {Connection, Connection, NotSet, NotSet}, // Arrows
1712  {NotSet, NotSet, NotSet, NotSet}, // NamedNonStationLocation
1714  {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, // points
1716  {Connection, Connection, NotSet, NotSet}, // Arrowed diagonals
1717  {NotSet, NotSet, NotSet, NotSet}, // Level crossing
1718  {Connection, Connection, NotSet, NotSet}, {Connection, Connection, NotSet, NotSet} // Underpasses/surface crossings
1719  };
1720 
1721  for(int x = 0; x < 17; x++)
1722  {
1723  FixedTrackPiece[x] = TFixedTrackPiece(x, TrackTypeArray[x], Links[x], Configs[x], TrackImageArray[x], SmallTrackImageArray[x]);
1724  }
1725  FixedTrackPiece[17] = TFixedTrackPiece(17, TrackTypeArray[17], Links[17], Configs[17], 0, 0);
1726 // 17 was the old text value so don't want any graphics (now disused)
1727  for(int x = 18; x < FirstUnusedSpeedTagNumber; x++)
1728  {
1729  FixedTrackPiece[x] = TFixedTrackPiece(x, TrackTypeArray[x], Links[x], Configs[x], TrackImageArray[x], SmallTrackImageArray[x]);
1730  }
1731 }
1732 
1733 // ---------------------------------------------------------------------------
1734 TGraphicElement::TGraphicElement() : OverlayPlotted(false), OriginalLoaded(false), ScreenSourceSet(false), ScreenGraphicLoaded(false),
1735  ExistingGraphicLoaded(false), Width(16), Height(16)
1736 {
1737  OriginalGraphic = new Graphics::TBitmap;
1738  OriginalGraphic->PixelFormat = pf8bit;
1739  OriginalGraphic->Width = Width;
1740  OriginalGraphic->Height = Height;
1741  OriginalGraphic->Transparent = false; // seems to default to false but set it to be sure, so no need to plot a blank before each replot
1742 }
1743 
1744 // ---------------------------------------------------------------------------
1745 
1746 TGraphicElement::TGraphicElement(int WidthIn, int HeightIn) : OverlayPlotted(false), OriginalLoaded(false), ScreenSourceSet(false), ScreenGraphicLoaded(false),
1747  ExistingGraphicLoaded(false), Width(WidthIn), Height(HeightIn)
1748 {
1749  OriginalGraphic = new Graphics::TBitmap;
1750  OriginalGraphic->PixelFormat = pf8bit;
1751  OriginalGraphic->Width = Width;
1752  OriginalGraphic->Height = Height;
1753  OriginalGraphic->Transparent = false; // seems to default to false but set it to be sure, so no need to plot a blank before each replot
1754 }
1755 
1756 // ---------------------------------------------------------------------------
1757 
1759 {
1760  delete OriginalGraphic;
1761 }
1762 
1763 // ---------------------------------------------------------------------------
1764 
1765 void TGraphicElement::SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
1766 {
1767  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetScreenHVSource," + AnsiString(HPosIn) + "," + AnsiString(VPosIn));
1768  HPos = HPosIn; // HPos & VPos are members of TGraphicElement
1769  VPos = VPosIn;
1770  int Left, Top; // can't use e.g. PointFlash.SourceRect.Left & Top directly as references as don't exist as objects in their own right
1771 
1772  Track->GetScreenPositionsFromTruePos(2, Left, Top, HPos, VPos);
1773  SourceRect.init(Left, Top, Left + Width, Top + Height);
1774  ScreenSourceSet = true;
1775  Utilities->CallLogPop(422);
1776 }
1777 
1778 // ---------------------------------------------------------------------------
1779 
1781 {
1782  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOriginalScreenGraphic");
1783  if(!OverlayLoaded)
1784  {
1785  throw Exception("Overlay not loaded in TGraphicElement::LoadOriginalScreenGraphic()");
1786  }
1787  if((OverlayGraphic->Width != 16) || (OverlayGraphic->Height != 16))
1788  {
1789  throw Exception("Overlay not 16x16 in TGraphicElement::LoadOriginalScreenGraphic()");
1790  }
1791  if(!ScreenSourceSet)
1792  {
1793  throw Exception("Source not set in TGraphicElement::LoadOriginalScreenGraphic()");
1794  }
1795  if(ExistingGraphicLoaded) // can only call one of the load functions
1796  {
1797  throw Exception("ExistingGraphicLoaded in TGraphicElement::LoadOriginalScreenGraphic()");
1798  }
1799  if(OverlayPlotted) // don't load from screen if overlay plotted
1800  {
1801  Utilities->CallLogPop(775);
1802  return;
1803  }
1804  TRect DestRect(0, 0, Width, Height);
1805 
1807  OriginalLoaded = true;
1808  ScreenGraphicLoaded = true;
1809  Utilities->CallLogPop(423);
1810 }
1811 
1812 // ---------------------------------------------------------------------------
1813 
1814 void TGraphicElement::LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
1815 /*
1816  Overrides size set in the constructor, SourceRect & HPos & VPos in SetScreenHVSource
1817 */
1818 {
1819  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOriginalExistingGraphic," + AnsiString(HOffset) + "," +
1820  AnsiString(VOffset) + "," + AnsiString(WidthIn) + "," + AnsiString(HeightIn));
1821  if(!OverlayLoaded)
1822  {
1823  throw Exception("Overlay not loaded in TGraphicElement::LoadOriginalExistingGraphic()");
1824  }
1825  if(!ScreenSourceSet) // has to be called to set HPos & VPos
1826  {
1827  throw Exception("Source not set in TGraphicElement::LoadOriginalExistingGraphic()");
1828  }
1829  if(ScreenGraphicLoaded) // can only call one of the load functions
1830  {
1831  throw Exception("ScreenGraphicLoaded in TGraphicElement::LoadOriginalExistingGraphic()");
1832  }
1833  Width = WidthIn;
1834  Height = HeightIn;
1835  OriginalGraphic->Width = Width;
1836  OriginalGraphic->Height = Height;
1837  HPos += HOffset; // originally set in SetScreenHVSource to position of H & V locations
1838  VPos += VOffset;
1839  TRect DestRect(0, 0, Width, Height);
1840 
1841  SourceRect.init(HOffset, VOffset, HOffset + Width, VOffset + Height);
1842  OriginalGraphic->Canvas->CopyRect(DestRect, Graphic->Canvas, SourceRect);
1843  OriginalLoaded = true;
1844  ExistingGraphicLoaded = true;
1845  Utilities->CallLogPop(424);
1846 }
1847 
1848 // ---------------------------------------------------------------------------
1849 
1850 void TGraphicElement::LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
1851 {
1852  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOverlayGraphic,");
1853  OverlayGraphic = Overlay;
1854  OverlayLoaded = true;
1855  Utilities->CallLogPop(425);
1856 }
1857 
1858 // ---------------------------------------------------------------------------
1859 
1861 {
1862  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotOverlay,");
1863  if(!OverlayLoaded)
1864  {
1865  throw Exception("Overlay not loaded in TGraphicElement::PlotOverlay()");
1866  }
1867  if(!OverlayPlotted)
1868  {
1869  Disp->PlotOutput(35, HPos, VPos, OverlayGraphic); // plot overlay
1870  Disp->Update();
1871  OverlayPlotted = true;
1872  }
1873  Utilities->CallLogPop(426);
1874 }
1875 
1876 // ---------------------------------------------------------------------------
1877 
1879 {
1880  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotOriginal,");
1881  if(OverlayPlotted)
1882  {
1883  if(!OriginalLoaded) // this comes after OverlayPlotted because may wish to 'try' to plot original even
1884  // when it isn't loaded in case it had been plotted - e.g. when change user modes
1885  {
1886  throw Exception("Original not loaded in TGraphicElement::PlotOriginal()");
1887  }
1888  Disp->PlotOutput(36, HPos, VPos, OriginalGraphic); // replot original
1889  Disp->Update(); // This was commented out originally but when in flashes much less frequent when points changing manually
1890  OverlayPlotted = false;
1891  }
1892  Utilities->CallLogPop(427);
1893 }
1894 
1895 // ---------------------------------------------------------------------------
1896 
1898 {
1899  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoTrack");
1900  bool TrackPresent = false;
1901 
1902  if(InactiveTrackVector.size() != 0)
1903  {
1904  Utilities->CallLogPop(1333);
1905  return(false);
1906  }
1907  else if(TrackVector.size() == 0)
1908  {
1909  Utilities->CallLogPop(1334);
1910  return(true);
1911  }
1912  else
1913  {
1914  for(unsigned int x = 0; x < TrackVector.size(); x++)
1915  {
1916  if((TrackElementAt(1042, x).SpeedTag != 0))
1917  {
1918  TrackPresent = true;
1919  }
1920  }
1921  }
1922  Utilities->CallLogPop(1335);
1923  return(!TrackPresent);
1924 }
1925 
1926 // ---------------------------------------------------------------------------
1927 
1928 bool TTrack::NoActiveTrack(int Caller)
1929 {
1930  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoActiveTrack");
1931  bool TrackPresent = false;
1932 
1933  if(TrackVector.size() == 0)
1934  {
1935  Utilities->CallLogPop(1582);
1936  return(true);
1937  }
1938  else
1939  {
1940  for(unsigned int x = 0; x < TrackVector.size(); x++)
1941  {
1942  if((TrackElementAt(1043, x).SpeedTag != 0))
1943  {
1944  TrackPresent = true;
1945  }
1946  break;
1947  }
1948  }
1949  Utilities->CallLogPop(1583);
1950  return(!TrackPresent);
1951 }
1952 
1953 // ---------------------------------------------------------------------------
1954 
1955 void TTrack::EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
1956 {
1957  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseTrackElement," + AnsiString(HLocInput) + "," +
1958  AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
1959  TrackEraseSuccessfulFlag = false;
1960 // TrackEraseSuccessfulFlag used for both track element and inactive element erase,
1961 // since have to match platforms as well as track
1962 // used to set TrackFinished to false if an element erased
1963 
1964  ErasedTrackVectorPosition = -1; // marker for no element erased
1965  AnsiString SName = "", ErrorString;
1967  THVPair TrackMapKeyPair, InactiveTrackMapKeyPair;
1968  TTrackMapIterator TrackMapPtr;
1969  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator;
1970 
1971  if(TrackVector.size() != 0)
1972  {
1973  TrackMapKeyPair.first = HLocInput;
1974  TrackMapKeyPair.second = VLocInput;
1975  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
1976  if(TrackMapPtr != TrackMap.end())
1977  {
1978  bool FoundFlag;
1979  int VecPos = GetVectorPositionFromTrackMap(37, HLocInput, VLocInput, FoundFlag);
1980  if(FoundFlag) // should find it as it's in the map
1981  {
1982  if(TrackElementAt(629, VecPos).FixedNamedLocationElement) // footcrossings only
1983  {
1984  SName = TrackElementAt(1, VecPos).LocationName;
1985  SNIt = FindNamedElementInLocationNameMultiMap(7, SName, TrackVector.begin() + VecPos, ErrorString);
1986  if(ErrorString != "")
1987  {
1988  throw Exception(ErrorString + " for EraseTrackElement 1");
1989  }
1990  LocationNameMultiMap.erase(SNIt);
1991  }
1992  TrackVector.erase(TrackVector.begin() + TrackMapPtr->second);
1993  // ensure erase vector element before map element as iterator no longer valid after a map erase
1994  TrackMap.erase(TrackMapPtr);
1995  FixedTrackArray.FixedTrackPiece[0].PlotFixedTrackElement(2, HLocInput, VLocInput); // plot a blank element
1996  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
1998  ResetAnyNonMatchingGaps(1); // in case the deleted element was a set gap
1999  if(SName != "")
2000  {
2001  EraseLocationAndActiveTrackElementNames(5, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
2002  int HPos, VPos;
2003  if(TextHandler->FindText(1, SName, HPos, VPos))
2004  {
2005  if(TextHandler->TextErase(5, HPos, VPos, SName))
2006  {
2007  ;
2008  } // condition not used
2009 
2010  }
2011  }
2012  ErasedTrackVectorPosition = VecPos;
2013  TrackEraseSuccessfulFlag = true;
2014  }
2015  }
2016  }
2017  if(InactiveTrackVector.size() != 0)
2018  {
2019  unsigned int VecPos;
2020  InactiveTrackMapKeyPair.first = HLocInput;
2021  InactiveTrackMapKeyPair.second = VLocInput;
2022  InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair);
2023  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
2024  {
2025  SName = "";
2026  VecPos = InactiveTrack2MultiMapIterator->second;
2027  if(InactiveTrackElementAt(0, VecPos).FixedNamedLocationElement)
2028  {
2029  SName = InactiveTrackElementAt(1, VecPos).LocationName;
2030  SNIt = FindNamedElementInLocationNameMultiMap(2, SName, InactiveTrackVector.begin() + VecPos, ErrorString);
2031  if(ErrorString != "")
2032  {
2033  throw Exception(ErrorString + " for EraseTrackElement 2A");
2034  }
2035  LocationNameMultiMap.erase(SNIt);
2036  }
2037  InactiveTrackVector.erase(InactiveTrackVector.begin() + InactiveTrack2MultiMapIterator->second); // if inactive can erase immediately
2038  // ensure erase vector element before map element as iterator no longer valid after a map erase
2039  InactiveTrack2MultiMap.erase(InactiveTrack2MultiMapIterator);
2040  FixedTrackArray.FixedTrackPiece[0].PlotFixedTrackElement(1, HLocInput, VLocInput); // plot a blank element
2041  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
2043  TrackEraseSuccessfulFlag = true;
2044  if(SName != "")
2045  {
2046  EraseLocationAndActiveTrackElementNames(3, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
2047  int HPos, VPos;
2048  if(TextHandler->FindText(2, SName, HPos, VPos))
2049  {
2050  if(TextHandler->TextErase(6, HPos, VPos, SName))
2051  {
2052  ;
2053  } // condition not used
2054 
2055  }
2056  }
2057  }
2058  if(InactiveTrackVector.size() != 0) // need to check again as last access may have erased the last element
2059  {
2060  InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // may be up to 2 elements (platforms) at same location
2061  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
2062  {
2063  SName = "";
2064  VecPos = InactiveTrack2MultiMapIterator->second;
2065  if(InactiveTrackElementAt(2, VecPos).FixedNamedLocationElement)
2066  {
2067  SName = InactiveTrackElementAt(3, VecPos).LocationName;
2068  SNIt = FindNamedElementInLocationNameMultiMap(3, SName, InactiveTrackVector.begin() + VecPos, ErrorString);
2069  if(ErrorString != "")
2070  {
2071  throw Exception(ErrorString + " for EraseTrackElement 2B");
2072  }
2073  LocationNameMultiMap.erase(SNIt);
2074  }
2075  InactiveTrackVector.erase(InactiveTrackVector.begin() + InactiveTrack2MultiMapIterator->second); // if inactive can erase immediately
2076  InactiveTrack2MultiMap.erase(InactiveTrack2MultiMapIterator);
2077  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
2079  if(SName != "")
2080  {
2081  EraseLocationAndActiveTrackElementNames(4, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
2082  int HPos, VPos;
2083  if(TextHandler->FindText(3, SName, HPos, VPos))
2084  {
2085  if(TextHandler->TextErase(7, HPos, VPos, SName))
2086  {
2087  ;
2088  } // condition not used
2089 
2090  }
2091  }
2092  }
2093  }
2094  }
2095  if(TrackEraseSuccessfulFlag)
2096  {
2097  CalcHLocMinEtc(2);
2098  SetTrackFinished(false);
2099  }
2100  if(InternalChecks)
2101  {
2102  CheckMapAndTrack(1); // test
2103  CheckMapAndInactiveTrack(1); // test
2104  CheckLocationNameMultiMap(6); // test
2105  }
2106  Utilities->CallLogPop(428);
2107 }
2108 
2109 // ---------------------------------------------------------------------------
2110 
2111 void TTrack::PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks)
2112 // TrackLinkingRequiredFlag only relates to elements that require track linking after plotting - used to set TrackFinished
2113 // to false in calling function. New at v2.2.0 new parameter 'Aspect' to ensure signals plotted with correct number of aspects (for pasting)
2114 // and also when zero and combined with SignalPost to indicate that adding track rather than pasting
2115 {
2116  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotAndAddTrackElement," + AnsiString(CurrentTag) + "," +
2117  AnsiString(HLocInput) + "," + AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
2118  bool PlatAllowedFlag = false;
2119 
2120  TrackLinkingRequiredFlag = false;
2121 /*
2122  Not erase, that covered separately.
2123  First check if Current SpeedButton assigned, then check if a platform and only
2124  permit if an appropriate trackpiece already there & not a same platform there.
2125  - can't enter a platform without track first.
2126  Then for non-platforms, check if a track piece already present at location &
2127  reject if so.
2128 */
2129 
2130  TLocationNameMultiMapEntry LocationNameEntry;
2131 
2132  LocationNameEntry.first = "";
2133  if(CurrentTag == 0)
2134  {
2135  Utilities->CallLogPop(429);
2136  return; // not assigned yet
2137  }
2138  TTrackElement TempTrackElement(FixedTrackArray.FixedTrackPiece[CurrentTag]);
2139 
2140  TempTrackElement.HLoc = HLocInput;
2141  TempTrackElement.VLoc = VLocInput;
2142  SetElementID(1, TempTrackElement); // TempTrackElement is the one to be added
2143 // new at version 0.6 - set signal aspect depending on build mode
2144 
2145  if(TempTrackElement.TrackType == SignalPost)
2146  {
2147  if(Aspect == 0) // new at v2.2.0, '0' and SignalPost together means that track being added & not pasted, because when
2148  // pasting a SignalPost can only have values 1 to 4
2149  {
2151  {
2152  TempTrackElement.SigAspect = TTrackElement::ThreeAspect;
2153  }
2155  {
2156  TempTrackElement.SigAspect = TTrackElement::TwoAspect;
2157  }
2159  {
2160  TempTrackElement.SigAspect = TTrackElement::GroundSignal;
2161  }
2162  else
2163  {
2164  TempTrackElement.SigAspect = TTrackElement::FourAspect;
2165  }
2166  }
2167  else if(Aspect == 1)
2168  {
2169  TempTrackElement.SigAspect = TTrackElement::GroundSignal;
2170  }
2171  else if(Aspect == 2)
2172  {
2173  TempTrackElement.SigAspect = TTrackElement::TwoAspect;
2174  }
2175  else if(Aspect == 3)
2176  {
2177  TempTrackElement.SigAspect = TTrackElement::ThreeAspect;
2178  }
2179  else
2180  {
2181  TempTrackElement.SigAspect = TTrackElement::FourAspect;
2182  }
2183  }
2184  bool FoundFlag = false, InactiveFoundFlag = false, NonStationOrLevelCrossingPresent = false, PlatformPresent = false;
2185  int VecPos = GetVectorPositionFromTrackMap(12, HLocInput, VLocInput, FoundFlag); // active track already there
2186  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(5, HLocInput, VLocInput, InactiveFoundFlag); // inactive track already there
2187  int InactiveSpeedTag1 = 0, InactiveSpeedTag2 = 0;
2188 
2189  if(InactiveFoundFlag) // check if a LocationName already there & if so disallow platform
2190  {
2192  {
2193  NonStationOrLevelCrossingPresent = true;
2194  }
2195  if(InactiveTrackElementAt(117, IMPair.first).TrackType == LevelCrossing)
2196  {
2197  NonStationOrLevelCrossingPresent = true;
2198  }
2199  if(InactiveTrackElementAt(5, IMPair.first).TrackType == Platform)
2200  {
2201  PlatformPresent = true;
2202  }
2203  // no need to check IMPair.second since if that exists it is because .first is a platform
2204  InactiveSpeedTag1 = InactiveTrackElementAt(6, IMPair.first).SpeedTag;
2205  InactiveSpeedTag2 = InactiveTrackElementAt(7, IMPair.second).SpeedTag; // note .first & .second will be same if only one present
2206  }
2207 // check platforms
2208  if(TempTrackElement.TrackType == Platform)
2209  {
2210  if(FoundFlag) // active track element already there
2211  {
2212  if(InactiveFoundFlag && ((TempTrackElement.SpeedTag == InactiveSpeedTag1) || (TempTrackElement.SpeedTag == InactiveSpeedTag2)))
2213  {
2214  ;
2215  }
2216  // same platform type already there so above keeps PlatAllowedFlag false
2217  else if((TempTrackElement.SpeedTag == 76) && (TopPlatAllowed.Contains(TrackElementAt(1044, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2218  // won't allow a same platform, as TopPlatAllowed not valid for a same platform <--NO, only checks active track, same plat disallowed by first line after if(FoundFlag)
2219  {
2220  PlatAllowedFlag = true;
2221  }
2222  else if((TempTrackElement.SpeedTag == 77) && (BotPlatAllowed.Contains(TrackElementAt(1045, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2223  {
2224  PlatAllowedFlag = true;
2225  }
2226  else if((TempTrackElement.SpeedTag == 78) && (LeftPlatAllowed.Contains(TrackElementAt(1046, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2227  {
2228  PlatAllowedFlag = true;
2229  }
2230  else if((TempTrackElement.SpeedTag == 79) && (RightPlatAllowed.Contains(TrackElementAt(1047, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2231  {
2232  PlatAllowedFlag = true;
2233  }
2234  if(PlatAllowedFlag)
2235  {
2236  TrackLinkingRequiredFlag = true; // needed in order to call LinkTrack
2237  TrackPush(1, TempTrackElement);
2238  SearchForAndUpdateLocationName(1, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2239  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2240  // Must be called AFTER TrackPush
2241  // No need to plot the element - Clearand ... called after this function called
2242  // set corresponding track element length to 100m & give message if was different drop in v2.4.0
2243  // note can only be Length01 since even if points then only the straight part can be adjacent to the platform
2244 // drop in v2.4.0 if(TrackElementAt(2, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2245 // AnsiString(TrackElementAt(3, VecPos).Length01) + "m. It will be reset to 100m since all platform track lengths are fixed at 100m");
2246 // TrackElementAt(4, VecPos).Length01 = DefaultTrackLength;
2247  if(InternalChecks)
2248  {
2249  CheckMapAndInactiveTrack(5); // test
2250  CheckLocationNameMultiMap(4); // test
2251  }
2252  Utilities->CallLogPop(430);
2253  return;
2254  }
2255  } // if(FoundFlag)
2256 
2257  Utilities->CallLogPop(431);
2258  return;
2259  } // if platform
2260 
2261 // check if element is a LocationName - OK if placed on an allowable track element, or on a blank element
2262  if(TempTrackElement.TrackType == NamedNonStationLocation)
2263  {
2264  if((FoundFlag && (NameAllowed.Contains(TrackElementAt(1048, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag) ||
2265  (!FoundFlag && !InactiveFoundFlag))
2266  // need to add && !NonStationOrLevelCrossingPresent, or better - !InactiveFoundFlag to above FoundFlag condition <-- OK done
2267  {
2268  TrackLinkingRequiredFlag = true; // needed in case have named a continuation, need to check if adjacent element named
2269  TrackPush(2, TempTrackElement);
2270  SearchForAndUpdateLocationName(2, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2271  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2272  if(VecPos > -1) // need to allow for non-station named locations that aren't on tracks
2273  {
2274 // drop in v2.4.0 if(TrackElementAt(830, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2275 // AnsiString(TrackElementAt(831, VecPos).Length01) + "m. It will be reset to 100m since all named location track lengths are fixed at 100m");
2276 // TrackElementAt(832, VecPos).Length01 = DefaultTrackLength; //NB named locations can only be placed at one track elements
2277  }
2278  if(InternalChecks)
2279  {
2280  CheckMapAndInactiveTrack(11); // test
2281  CheckLocationNameMultiMap(12); // test
2282  }
2283  Utilities->CallLogPop(432);
2284  return;
2285  }
2286  else
2287  {
2288  Utilities->CallLogPop(433);
2289  return;
2290  }
2291  }
2292 // check if a level crossing - OK if placed on a plain straight track
2293  if(TempTrackElement.TrackType == LevelCrossing)
2294  {
2295  if(FoundFlag && (LevelCrossingAllowed.Contains(TrackElementAt(1049, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag)
2296  {
2297  TrackPush(11, TempTrackElement);
2298  PlotRaisedLinkedLevelCrossingBarriers(0, TrackElementAt(1050, VecPos).SpeedTag, TempTrackElement.HLoc, TempTrackElement.VLoc, Display); //always plots red
2299 // no need for reference to LC element as can't be open
2300  TrackLinkingRequiredFlag = true;
2301  Utilities->CallLogPop(1907);
2302  return;
2303  }
2304  else
2305  {
2306  Utilities->CallLogPop(1906);
2307  return; // was a level crossing but can't place it for some reason
2308  }
2309  }
2310 
2311 // check if another element already there
2312  else if(FoundFlag || InactiveFoundFlag)
2313  {
2314  Utilities->CallLogPop(434);
2315  return; // something already there (active or inactive track)
2316  }
2317 // add LocationName if a FixedNamedLocationElement by checking for any adjacent names, then give all linked named location
2318 // elements the same name - in case had linked 2 separately named locations - all get the one name that it finds
2319 // first from an adjacent element search, also non-named location elements at platform locations have timetable name set
2320 // do this after pushed into vector so that can use EnterLocationName
2321 
2322  if(TempTrackElement.FixedNamedLocationElement) // concourse or footcrossing (platforms & named non-station locations already dealt with)
2323  {
2324  TrackPush(3, TempTrackElement);
2325  SearchForAndUpdateLocationName(3, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2326  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2327  }
2328  else if(TempTrackElement.TrackType == Points)
2329  {
2330  TrackPush(4, TempTrackElement);
2331  bool BothPointFillets = true;
2332  PlotPoints(6, TempTrackElement, Display, BothPointFillets);
2333  }
2334  else if(TempTrackElement.TrackType == SignalPost)
2335  {
2336  TrackPush(10, TempTrackElement);
2337  PlotSignal(12, TempTrackElement, Display);
2338  }
2339  else
2340  {
2341  TrackPush(5, TempTrackElement);
2342  TempTrackElement.PlotVariableTrackElement(1, Display); // all named locations already dealt with so no ambiguity between striped & non-striped
2343  }
2344  if((TempTrackElement.TrackType != Concourse) && (TempTrackElement.TrackType != Parapet))
2345  {
2346  TrackLinkingRequiredFlag = true; // plats & NamedLocs aleady dealt with
2347  }
2348  if(InternalChecks)
2349  {
2350  CheckMapAndTrack(2); // test
2351  CheckMapAndInactiveTrack(2); // test
2352  CheckLocationNameMultiMap(5); // test
2353  }
2354  Utilities->CallLogPop(2062);
2355 }
2356 
2357 // ---------------------------------------------------------------------------
2358 
2359 void TTrack::PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag,
2360  bool InternalChecks)
2361 // new at v2.2.0 - similar to above but keeping speed & length attributes (for pasting) and also pastes location names
2362 {
2363  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPastedTrackElementWithAttributes," + AnsiString(HLocInput) + "," +
2364  AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
2365  bool PlatAllowedFlag = false;
2366 
2367  TrackLinkingRequiredFlag = false;
2368  TLocationNameMultiMapEntry LocationNameEntry;
2369 
2370  LocationNameEntry.first = "";
2371  if(TempTrackElement.SpeedTag == 0)
2372  {
2373  Utilities->CallLogPop(2063);
2374  return; // not assigned yet
2375  }
2376  TempTrackElement.HLoc = HLocInput;
2377  TempTrackElement.VLoc = VLocInput;
2378  for(int x = 0; x < 4; x++) // unset any gaps
2379  {
2380  if(TempTrackElement.Config[x] == Gap)
2381  {
2382  TempTrackElement.ConnLinkPos[x] = -1;
2383  }
2384  TempTrackElement.Conn[x] = -1;
2385  }
2386  SetElementID(5, TempTrackElement); // TempTrackElement is the one to be added
2387 // new at version 0.6 - set signal aspect depending on build mode
2388  bool FoundFlag = false, InactiveFoundFlag = false, NonStationOrLevelCrossingPresent = false, PlatformPresent = false;
2389  int VecPos = GetVectorPositionFromTrackMap(56, HLocInput, VLocInput, FoundFlag); // active track already there
2390 
2391  // if find an active track element (as has been pasted into track vector when dealing with inactive elements in SelectVector)
2392  // )set its ActiveTrackElementName to same name as the inactive element (from SelectVector). Note that can't use LocationName
2393  // for the active track element because these aren't set
2394  // if don't do this then get a mismatch error during map checks later
2395 
2396  // if(FoundFlag) TrackElementAt(xx, VecPos).ActiveTrackElementName = TempTrackElement.LocationName; //doesn't work!!
2397 
2398  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(26, HLocInput, VLocInput, InactiveFoundFlag); // inactive track already there
2399  int InactiveSpeedTag1 = 0, InactiveSpeedTag2 = 0;
2400 
2401  if(InactiveFoundFlag) // check if a LocationName already there & if so disallow platform
2402  {
2403  if(InactiveTrackElementAt(119, IMPair.first).TrackType == NamedNonStationLocation)
2404  {
2405  NonStationOrLevelCrossingPresent = true;
2406  }
2407  if(InactiveTrackElementAt(120, IMPair.first).TrackType == LevelCrossing)
2408  {
2409  NonStationOrLevelCrossingPresent = true;
2410  }
2411  if(InactiveTrackElementAt(121, IMPair.first).TrackType == Platform)
2412  {
2413  PlatformPresent = true;
2414  }
2415  // no need to check IMPair.second since if that exists it is because .first is a platform
2416  InactiveSpeedTag1 = InactiveTrackElementAt(122, IMPair.first).SpeedTag;
2417  InactiveSpeedTag2 = InactiveTrackElementAt(123, IMPair.second).SpeedTag; // note .first & .second will be same if only one present
2418  }
2419 // check platforms
2420  if(TempTrackElement.TrackType == Platform)
2421  {
2422  if(FoundFlag) // active track element already there
2423  {
2424  if(InactiveFoundFlag && ((TempTrackElement.SpeedTag == InactiveSpeedTag1) || (TempTrackElement.SpeedTag == InactiveSpeedTag2)))
2425  {
2426  ;
2427  }
2428  // same platform type already there so above keeps PlatAllowedFlag false
2429  else if((TempTrackElement.SpeedTag == 76) && (TopPlatAllowed.Contains(TrackElementAt(1051, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2430  // won't allow a same platform, as TopPlatAllowed not valid for a same platform <--NO, only checks active track, same plat disallowed by first line after if(FoundFlag)
2431  {
2432  PlatAllowedFlag = true;
2433  }
2434  else if((TempTrackElement.SpeedTag == 77) && (BotPlatAllowed.Contains(TrackElementAt(1052, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2435  {
2436  PlatAllowedFlag = true;
2437  }
2438  else if((TempTrackElement.SpeedTag == 78) && (LeftPlatAllowed.Contains(TrackElementAt(1053, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2439  {
2440  PlatAllowedFlag = true;
2441  }
2442  else if((TempTrackElement.SpeedTag == 79) && (RightPlatAllowed.Contains(TrackElementAt(1054, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2443  {
2444  PlatAllowedFlag = true;
2445  }
2446  if(PlatAllowedFlag)
2447  {
2448  TrackLinkingRequiredFlag = true; // needed in order to call LinkTrack
2449  TrackPush(12, TempTrackElement);
2450 // if(!CopyFlag) // don't need this for copy - yes we do, this is so a location will be named if pasted next to a named location - condition removed at v2.6.0
2451  {
2452  SearchForAndUpdateLocationName(4, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2453  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2454  }
2455  // Must be called AFTER TrackPush
2456 // No need to plot the element - Clearand ... called after this function called
2457  // set corresponding track element length to 100m & give message if was different drop in v2.4.0
2458  // note can only be Length01 since even if points then only the straight part can be adjacent to the platform
2459 // drop in v2.4.0 if(TrackElementAt(907, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2460 // AnsiString(TrackElementAt(908, VecPos).Length01) + "m. It will be reset to 100m since all platform track lengths are fixed at 100m");
2461 // TrackElementAt(909, VecPos).Length01 = DefaultTrackLength;
2462  if(InternalChecks)
2463  {
2464  CheckMapAndInactiveTrack(12); // test
2465  CheckLocationNameMultiMap(20); // test
2466  }
2467  Utilities->CallLogPop(2064);
2468  return;
2469  }
2470  } // if(FoundFlag)
2471 
2472  Utilities->CallLogPop(2065);
2473  return;
2474  } // if platform
2475 
2476 // check if element is a LocationName - OK if placed on an allowable track element, or on a blank element
2477  if(TempTrackElement.TrackType == NamedNonStationLocation)
2478  {
2479  if((FoundFlag && (NameAllowed.Contains(TrackElementAt(1055, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag) ||
2480  (!FoundFlag && !InactiveFoundFlag))
2481  // need to add && !NonStationOrLevelCrossingPresent, or better - !InactiveFoundFlag to above FoundFlag condition <-- OK done
2482  {
2483  TrackLinkingRequiredFlag = true; // needed in case have named a continuation, need to check if adjacent element named
2484  TrackPush(13, TempTrackElement);
2485 // if(!CopyFlag) // don't need this for copy - yes we do, this is so a location will be named if pasted next to a named location - condition removed at v2.6.0
2486  {
2487  SearchForAndUpdateLocationName(5, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2488  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2489  }
2490  if(VecPos > -1) // need to allow for non-station named locations that aren't on tracks
2491  {
2492 // drop in v2.4.0 if(TrackElementAt(910, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2493 // AnsiString(TrackElementAt(911, VecPos).Length01) + "m. It will be reset to 100m since all named location track lengths are fixed at 100m");
2494 // TrackElementAt(912, VecPos).Length01 = DefaultTrackLength; //NB named locations can only be placed at one track elements
2495  }
2496  if(InternalChecks)
2497  {
2498  CheckMapAndInactiveTrack(13); // test
2499  CheckLocationNameMultiMap(21); // test
2500  }
2501  Utilities->CallLogPop(2066);
2502  return;
2503  }
2504  else
2505  {
2506  Utilities->CallLogPop(2067);
2507  return;
2508  }
2509  }
2510 // check if a level crossing - OK if placed on a plain straight track
2511  if(TempTrackElement.TrackType == LevelCrossing)
2512  {
2513  if(FoundFlag && (LevelCrossingAllowed.Contains(TrackElementAt(1056, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag)
2514  {
2515  TrackPush(14, TempTrackElement);
2516  PlotRaisedLinkedLevelCrossingBarriers(3, TrackElementAt(1057, VecPos).SpeedTag, TempTrackElement.HLoc, TempTrackElement.VLoc, Display); //always plots red
2517 // no need for reference to LC element as can't be open
2518  TrackLinkingRequiredFlag = true;
2519  Utilities->CallLogPop(2068);
2520  return;
2521  }
2522  else
2523  {
2524  Utilities->CallLogPop(2069);
2525  return; // was a level crossing but can't place it for some reason
2526  }
2527  }
2528 
2529 // check if another element already there
2530  else if(FoundFlag || InactiveFoundFlag)
2531  {
2532  Utilities->CallLogPop(2070);
2533  return; // something already there (active or inactive track)
2534  }
2535 // add LocationName if a FixedNamedLocationElement by checking for any adjacent names, then give all linked named location
2536 // elements the same name - in case had linked 2 separately named locations - all get the one name that it finds
2537 // first from an adjacent element search, also non-named location elements at platform locations have timetable name set
2538 // do this after pushed into vector so that can use EnterLocationName
2539 
2540  if(TempTrackElement.FixedNamedLocationElement) // concourse or footcrossing (platforms & named non-station locations already dealt with)
2541  {
2542  TrackPush(15, TempTrackElement);
2543  SearchForAndUpdateLocationName(6, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2544  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2545  }
2546  else if(TempTrackElement.TrackType == Points)
2547  {
2548  TrackPush(16, TempTrackElement);
2549  bool BothPointFillets = true;
2550  PlotPoints(7, TempTrackElement, Display, BothPointFillets);
2551  }
2552  else if(TempTrackElement.TrackType == SignalPost)
2553  {
2554  TrackPush(17, TempTrackElement);
2555  PlotSignal(14, TempTrackElement, Display);
2556  }
2557  else
2558  {
2559  TrackPush(18, TempTrackElement);
2560  TempTrackElement.PlotVariableTrackElement(6, Display); // all named locations already dealt with so no ambiguity between striped & non-striped
2561  }
2562  if((TempTrackElement.TrackType != Concourse) && (TempTrackElement.TrackType != Parapet))
2563  {
2564  TrackLinkingRequiredFlag = true; // plats & NamedLocs aleady dealt with
2565  }
2566  if(InternalChecks)
2567  {
2568  CheckMapAndTrack(12); // test
2569  CheckMapAndInactiveTrack(14); // test
2570  CheckLocationNameMultiMap(22); // test
2571  }
2572  Utilities->CallLogPop(2071);
2573 }
2574 
2575 // ---------------------------------------------------------------------------
2576 
2577 bool TTrack::TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
2578 // GiveMessages relates to the call to LinkTrack or LinkTrackNoMessages
2579 // return bool = true for success
2580 // LocError = true for location error & HLoc & VLoc to be inverted
2581 {
2582  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TryToConnectTrack," + AnsiString((short)GiveMessages));
2583  LocError = false;
2584  SetTrackFinished(false);
2585  if(TrackVector.size() == 0)
2586  {
2587  Utilities->CallLogPop(437);
2588  return(false);
2589  }
2590  if(GapsUnset(7))
2591  {
2592  if(GiveMessages)
2593  {
2594  ShowMessage("Gaps must be set before track can be validated");
2595  }
2596  Utilities->CallLogPop(1135);
2597  return(false);
2598  }
2599 // below sets all Conns and CLks to -1 except for gapjumps that match and are properly set,
2600 // returns true for any unset gaps
2602  {
2603  // can keep this exception as protected by the GapsUnset call above
2604  throw Exception("Error, gaps unset when TryToConnectTrack called");
2605  }
2607  CheckGapMap(1); // test
2608 // Gap connections now securely defined
2609 
2610  CheckMapAndTrack(8); // test
2611 
2612 // Perform a pre-check prior to TrackMap being compiled
2613  if(GiveMessages)
2614  {
2615  if(!LinkTrack(1, LocError, HLoc, VLoc, false))
2616  {
2617  Utilities->CallLogPop(439);
2618  return(false);
2619  }
2620  }
2621  else
2622  {
2623  if(!LinkTrackNoMessages(1, false))
2624  {
2625  Utilities->CallLogPop(1131);
2626  return(false);
2627  }
2628  }
2629 // here if pre-check successful
2630  if(!RepositionAndMapTrack(0))
2631  {
2632  ShowMessage("Error in RepositionAndMapTrack during TryToConnectTrack. Railway file is corrupt, further use may cause a system crash");
2633  Utilities->CallLogPop(1138);
2634  return(false);
2635  }
2636 // now perform the final assembly - FinalCall = true
2637  if(GiveMessages)
2638  {
2639  if(!LinkTrack(2, LocError, HLoc, VLoc, true))
2640  {
2641  Utilities->CallLogPop(1116);
2642  return(false);
2643  }
2644  }
2645  else
2646  {
2647  if(!LinkTrackNoMessages(2, true))
2648  {
2649  Utilities->CallLogPop(1132);
2650  return(false);
2651  }
2652  }
2653 // success
2654 
2655  PopulateLCVector(0);
2656  CheckGapMap(2); // test
2657  CheckMapAndTrack(3); // test
2658  CheckMapAndInactiveTrack(3); // test
2659  CheckLocationNameMultiMap(9); // test
2660  SetTrackFinished(true);
2661 
2662 // Build ContinuationNameMap
2663  std::pair<AnsiString, char>TempMapPair;
2664 
2665  ContinuationNameMap.clear();
2666  for(int x = 0; x < Track->TrackVectorSize(); x++)
2667  {
2668  if((Track->TrackElementAt(1058, x).TrackType == Continuation) && (Track->TrackElementAt(1059, x).ActiveTrackElementName != ""))
2669  {
2670  TempMapPair.first = Track->TrackElementAt(1060, x).ActiveTrackElementName;
2671  TempMapPair.second = 'x'; // unused
2672  ContinuationNameMap.insert(TempMapPair);
2673  }
2674  }
2675 
2676 //check (provided TrackFinished is true) if any named (red) locations are without platforms, ie concourses only or concourses and foot crossings
2677 //(don't report blue areas without track as these unlikely to be mistakes)
2678 
2679  if(TrackFinished)
2680  {
2681  AnsiString Name = "";
2682  typedef std::list<AnsiString> TNoPlatsList;
2683  TNoPlatsList::iterator NPLIt;
2684  TNoPlatsList NoPlatsList;
2685  typedef std::list<AnsiString> TLocNameList;
2686  TLocNameList LocNameList; //single entry for each name
2689  for(TLocationNameMultiMapIterator LNMMIt = LocationNameMultiMap.begin(); LNMMIt != LocationNameMultiMap.end(); LNMMIt++)
2690  {
2691  LocNameList.push_back(LNMMIt->first);
2692  }
2693  LocNameList.sort();
2694  LocNameList.unique();
2695  for(TLocNameList::iterator LNLIt = LocNameList.begin(); LNLIt != LocNameList.end(); LNLIt++)
2696  {
2697  Name = *LNLIt;
2698  MMRange = LocationNameMultiMap.equal_range(Name);
2699  if(MMRange.first == MMRange.second) //can't find it - should always do but include as a safeguard
2700  {
2701  continue;
2702  }
2703  for(TLocationNameMultiMapIterator LNMMIt = MMRange.first; LNMMIt != MMRange.second; LNMMIt++)
2704  {
2705  if((LNMMIt->second) < 0) //active track element
2706  {
2707  if(TrackElementAt(1401, -1 - LNMMIt->second).TrackType != FootCrossing)
2708  {
2709  break;
2710  }
2711  }
2712  else //inactive
2713  {
2714  if(InactiveTrackElementAt(1402, LNMMIt->second).TrackType != Concourse)
2715  {
2716  break;
2717  }
2718  }
2719  TempIt = MMRange.second;
2720  if(LNMMIt == --TempIt) //reached last named element & all concourses or foot crossings
2721  {
2722  NoPlatsList.push_back(Name);
2723  }
2724  }
2725  }
2726  if(!NoPlatsList.empty())
2727  {
2728  AnsiString NoPlatsAnsiList = "";
2729  for(NPLIt = NoPlatsList.begin(); NPLIt != NoPlatsList.end(); NPLIt++)
2730  {
2731  NoPlatsAnsiList += *NPLIt + '\n';
2732  }
2733  if(!NoPlatsMessageSent)
2734  {
2735  if(NoPlatsList.size() > 1)
2736  {
2737  ShowMessage("Please note: the following locations have no platforms, trains won't be able to stop or pass there:-\n\n" + NoPlatsAnsiList + "\nThis message will not be shown again.");
2738  }
2739  else
2740  {
2741  ShowMessage("Please note: the following location has no platforms, trains won't be able to stop or pass there:-\n\n" + NoPlatsAnsiList + "\nThis message will not be shown again.");
2742  }
2743  NoPlatsMessageSent = true;
2744  }
2745  }
2746  }
2747  Utilities->CallLogPop(440);
2748  return(true);
2749 }
2750 
2751 // ---------------------------------------------------------------------------
2752 bool TTrack::ErrorInTrackBeforeSetGaps(int Caller, int &HLoc, int &VLoc)
2753 // unused - too time-consuming - double brute force search
2754 {
2755  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ErrorInTrackBeforeSetGaps");
2756  int NewHLoc, NewVLoc;
2757  bool ConnectionFoundFlag, LinkFoundFlag;
2758 
2759  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
2760  {
2761  for(unsigned int y = 0; y < 4; y++) // check all links for each element
2762  {
2763  if(TrackElementAt(1061, x).Link[y] <= 0)
2764  {
2765  continue; // no link
2766  }
2767  if(TrackElementAt(1062, x).Config[y] == End)
2768  {
2769  continue; // buffer or continuation
2770  }
2771  if(TrackElementAt(1063, x).Config[y] == Gap)
2772  {
2773  continue; // gap jump
2774  }
2775  // get required H & V for track element joining link 'y'
2776  NewHLoc = TrackElementAt(1064, x).HLoc + LinkHVArray[TrackElementAt(1065, x).Link[y]][0];
2777  NewVLoc = TrackElementAt(1066, x).VLoc + LinkHVArray[TrackElementAt(1067, x).Link[y]][1];
2778  // find track element if present
2779  ConnectionFoundFlag = false;
2780  for(unsigned int z = 0; z < TrackVector.size(); z++)
2781  {
2782 // if(TrackElementAt(5, z).TrackType == Platform)
2783 // continue; //skip platforms
2784  if((TrackElementAt(1068, z).HLoc == NewHLoc) && (TrackElementAt(1069, z).VLoc == NewVLoc))
2785  {
2786  ConnectionFoundFlag = true;
2787  // find connecting link in the newly found track element if there is one
2788  LinkFoundFlag = false;
2789  for(unsigned int a = 0; a < 4; a++)
2790  {
2791  if(TrackElementAt(1070, z).Link[a] == (10 - TrackElementAt(1071, x).Link[y]))
2792  {
2793  LinkFoundFlag = true;
2794  }
2795  }
2796  // if there isn't a corresponding link set the invert values for the offending element
2797  if(!LinkFoundFlag)
2798  {
2799  HLoc = TrackElementAt(1072, x).HLoc;
2800  VLoc = TrackElementAt(1073, x).VLoc;
2801  Utilities->CallLogPop(441);
2802  return(true);
2803  }
2804  break; // success, so break out of 'z' loop
2805  } // if((TrackElementAt(, z).HLoc== NewHLoc) &&....
2806 
2807  } // for z...
2808  // if there isn't a connection set the invert values for the offending element
2809  if(!ConnectionFoundFlag)
2810  {
2811  HLoc = TrackElementAt(1074, x).HLoc;
2812  VLoc = TrackElementAt(1075, x).VLoc;
2813  Utilities->CallLogPop(442);
2814  return(true);
2815  }
2816  } // for y....
2817  } // for x...
2818  Utilities->CallLogPop(443);
2819  return(false); // all OK
2820 }
2821 
2822 // ---------------------------------------------------------------------------
2823 
2824 bool TTrack::FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement) // true if find one
2825 {
2826  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindNonPlatformMatch," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
2827  TrackElement.LogTrack(0));
2828  bool FoundFlag;
2829 
2830  Position = GetVectorPositionFromTrackMap(13, HLoc, VLoc, FoundFlag);
2831  if(FoundFlag)
2832  {
2833  TrackElement = TrackElementAt(1076, Position);
2834  }
2835  Utilities->CallLogPop(444);
2836  return(FoundFlag);
2837 }
2838 
2839 // ---------------------------------------------------------------------------
2840 
2842 {
2843  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ReturnNextTrackElement");
2844  if(NextTrackElementPtr >= TrackVector.end())
2845  {
2846  Utilities->CallLogPop(1336);
2847  return(false);
2848  }
2849  Next = *NextTrackElementPtr;
2851  Utilities->CallLogPop(1337);
2852  return(true);
2853 }
2854 
2855 // ---------------------------------------------------------------------------
2856 
2858 {
2859  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ReturnNextInactiveTrackElement");
2861  {
2862  Utilities->CallLogPop(1338);
2863  return(false);
2864  }
2865  Next = *NextTrackElementPtr;
2867  Utilities->CallLogPop(1339);
2868  return(true);
2869 }
2870 
2871 // ---------------------------------------------------------------------------
2872 
2873 int TTrack::NumberOfGaps(int Caller)
2874 
2875 {
2876  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NumberOfGaps");
2877  int Count = 0;
2878 
2879  if(TrackVector.size() == 0)
2880  {
2881  Utilities->CallLogPop(1340);
2882  return(0);
2883  }
2884  for(unsigned int x = 0; x < TrackVector.size(); x++)
2885  {
2886  if(TrackElementAt(1077, x).TrackType == GapJump)
2887  {
2888  Count++;
2889  }
2890  }
2891  Utilities->CallLogPop(1341);
2892  return(Count);
2893 }
2894 
2895 // ---------------------------------------------------------------------------
2897 // above sets all Conns and CLks to -1 except for gapjumps that match and are properly set
2898 // returns true for any unset gaps
2899 {
2900  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetConnClkCheckUnsetGapJumps");
2901  bool UnsetGaps = false;
2902 
2903  if(TrackVector.size() == 0)
2904  {
2905  Utilities->CallLogPop(445);
2906  return(false);
2907  }
2908  for(unsigned int x = 0; x < TrackVector.size(); x++)
2909  {
2910  if(TrackElementAt(1078, x).TrackType != GapJump)
2911  {
2912  for(unsigned int y = 0; y < 4; y++)
2913  {
2914  TrackElementAt(1079, x).Conn[y] = -1;
2915  TrackElementAt(1080, x).ConnLinkPos[y] = -1;
2916  }
2917  }
2918  else // GapJump
2919  {
2920 // int tempint = TrackElementAt(, x).Conn[0);
2921 
2922  if(TrackElementAt(1081, x).Conn[0] == -1) // unset if -1
2923  {
2924  for(unsigned int y = 0; y < 4; y++)
2925  {
2926  TrackElementAt(1082, x).Conn[y] = -1;
2927  TrackElementAt(1083, x).ConnLinkPos[y] = -1;
2928  }
2929  UnsetGaps = true;
2930  continue; // to next 'x'
2931  }
2932  else // set, but may not have matching element, or that element may not be set
2933  {
2934  for(unsigned int y = 1; y < 4; y++) // reset the non-gap values anyway, gap always at position 0
2935  {
2936  TrackElementAt(1084, x).Conn[y] = -1;
2937  TrackElementAt(1085, x).ConnLinkPos[y] = -1;
2938  }
2939 
2940  if(TrackElementAt(1086, TrackElementAt(1104, x).Conn[0]).TrackType != GapJump)
2941  // check that the element pointed to by the gap link is a GapJump & if not clear Conns & CLks & reset Lk[0]
2942  {
2943  for(unsigned int y = 0; y < 4; y++)
2944  {
2945  TrackElementAt(1087, x).Conn[y] = -1;
2946  TrackElementAt(1088, x).ConnLinkPos[y] = -1;
2947  }
2948  UnsetGaps = true;
2949  continue; // to next 'x'
2950  }
2951 // here if gap connection is itself a GapJump
2952  if(TrackElementAt(1089, TrackElementAt(1105, x).Conn[0]).Conn[0] != (int)x)
2953  // check that the element pointed to by the gap link is a GapJump & that its gap link points back to 'x'
2954  // if not clear Conns & CLks & reset Lk[0]
2955  {
2956  for(unsigned int y = 0; y < 4; y++)
2957  {
2958  TrackElementAt(1090, x).Conn[y] = -1;
2959  TrackElementAt(1091, x).ConnLinkPos[y] = -1;
2960  }
2961  UnsetGaps = true;
2962  continue; // to next 'x'
2963  }
2964 // here if gap connection itself points back to 'x' so these two GapJumps match properly
2965 // hence no more action needed on these Conns & CLks
2966  }
2967  } // else //gap jump
2968 
2969  } // for x...
2970  Utilities->CallLogPop(446);
2971  return(UnsetGaps);
2972 }
2973 
2974 // ---------------------------------------------------------------------------
2975 
2976 void TTrack::LoadTrack(int Caller, std::ifstream& VecFile, bool &GraphicsFollow)
2977 {
2978 // VecFile already open and its pointer at right place on calling
2979  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadTrack");
2980  int TempInt;
2981 
2982  TrackClear(1);
2983 // load track elements
2984  int NumberOfActiveElements = 0;
2985 
2986  GraphicsFollow = false;
2987  NumberOfActiveElements = Utilities->LoadFileInt(VecFile);
2988  AnsiString MarkerString = Utilities->LoadFileString(VecFile); // **Active elements** marker, if last character is '1' then there are graphics to be loaded
2989 
2990  if(MarkerString[MarkerString.Length()] == '1')
2991  {
2992  GraphicsFollow = true;
2993  }
2994  for(int x = 0; x < NumberOfActiveElements; x++)
2995  {
2996  VecFile >> TempInt; // TrackVectorNumber, not used
2997  VecFile >> TempInt; // SpeedTag
2998  TTrackElement TrackElement(FixedTrackArray.FixedTrackPiece[TempInt]);
2999  VecFile >> TempInt;
3000  TrackElement.HLoc = TempInt;
3001  VecFile >> TempInt;
3002  TrackElement.VLoc = TempInt;
3003  if(TrackElement.TrackType == GapJump)
3004  {
3005  VecFile >> TempInt;
3006  TrackElement.ConnLinkPos[0] = TempInt;
3007  VecFile >> TempInt;
3008  TrackElement.Conn[0] = TempInt;
3009  }
3010  if((TrackElement.TrackType == SignalPost) || (TrackElement.TrackType == Points))
3011  {
3012  VecFile >> TempInt;
3013  TrackElement.Attribute = TempInt;
3014  }
3015  if(TrackElement.TrackType == SignalPost)
3016  {
3017  VecFile >> TempInt;
3018  if(TempInt == 0)
3019  {
3020  TrackElement.CallingOnSet = false;
3021  }
3022  else
3023  {
3024  TrackElement.CallingOnSet = true;
3025  }
3026  }
3027  VecFile >> TempInt;
3028  TrackElement.Length01 = TempInt;
3029  VecFile >> TempInt;
3030  TrackElement.Length23 = TempInt;
3031  VecFile >> TempInt;
3032  if((TempInt != -1) && (TempInt < 10))
3033  {
3034  TempInt = 10; // added at v0.6 to ensure old railway speed limits at least 10km/h
3035  }
3036  if((TempInt != -1) && (TempInt > TTrain::MaximumSpeedLimit))
3037  {
3038  TempInt = TTrain::MaximumSpeedLimit; // added at v2.1.0 to limit max speed
3039  }
3040  TrackElement.SpeedLimit01 = TempInt;
3041  VecFile >> TempInt;
3042  if((TempInt != -1) && (TempInt < 10))
3043  {
3044  TempInt = 10; // added at v0.6 to ensure old railway speed limits at least 10km/h
3045  }
3046  if((TempInt != -1) && (TempInt > TTrain::MaximumSpeedLimit))
3047  {
3048  TempInt = TTrain::MaximumSpeedLimit; // added at v2.1.0 to limit max speed
3049  }
3050  TrackElement.SpeedLimit23 = TempInt;
3051 
3052  TrackElement.LocationName = Utilities->LoadFileString(VecFile);
3053  TrackElement.ActiveTrackElementName = Utilities->LoadFileString(VecFile);
3054  SetElementID(0, TrackElement);
3055  AnsiString Marker = Utilities->LoadFileString(VecFile); // marker
3056 // new for v0.6
3057  if(TrackElement.TrackType == SignalPost)
3058  {
3059  if(Marker[1] == '3')
3060  {
3061  TrackElement.SigAspect = TTrackElement::ThreeAspect;
3062  }
3063  else if(Marker[1] == '2')
3064  {
3065  TrackElement.SigAspect = TTrackElement::TwoAspect;
3066  }
3067  else if(Marker[1] == 'G')
3068  {
3069  TrackElement.SigAspect = TTrackElement::GroundSignal;
3070  }
3071  else
3072  {
3073  TrackElement.SigAspect = TTrackElement::FourAspect;
3074  }
3075  }
3076  if(TrackElement.SpeedTag != 0)
3077  {
3078  TrackPush(8, TrackElement); // don't save default elements (now dispensed with)
3079  }
3080  }
3081  int NumberOfInactiveElements = 0;
3082 
3083  NumberOfInactiveElements = Utilities->LoadFileInt(VecFile);
3084  Utilities->LoadFileString(VecFile); // **Inactive elements** marker
3085  for(int x = 0; x < NumberOfInactiveElements; x++)
3086  {
3087  VecFile >> TempInt; // InactiveTrackVectorNumber - not used, only used for identification in file
3088  VecFile >> TempInt; // SpeedTag
3089  TTrackElement TrackElement(FixedTrackArray.FixedTrackPiece[TempInt]);
3090  VecFile >> TempInt;
3091  TrackElement.HLoc = TempInt;
3092  VecFile >> TempInt;
3093  TrackElement.VLoc = TempInt;
3094  TrackElement.LocationName = Utilities->LoadFileString(VecFile);
3095  SetElementID(3, TrackElement);
3096  TrackPush(9, TrackElement);
3097  Utilities->LoadFileString(VecFile); // marker
3098  }
3099  bool LocError = false; // needed for TryToConnectTrack but not used
3100  int H = -1, V = -1; // needed for TryToConnectTrack but not used
3101 
3102  if(TryToConnectTrack(2, LocError, H, V, false)) // false for don't give messages
3103  {
3104  SetTrackFinished(true);
3105  }
3106  else
3107  {
3108  SetTrackFinished(false);
3109  }
3110 // CheckMapAndTrack(9); all these checked in TryToConnectTrack
3111 // CheckMapAndInactiveTrack(8);
3112 // CheckLocationNameMultiMap(10);
3113  Utilities->CallLogPop(448);
3114 }
3115 
3116 // ---------------------------------------------------------------------------
3117 
3118 void TTrack::LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
3119 {
3120 // VecFile already open and its pointer at right place on calling
3121  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadGraphics, " + GraphicsPath);
3122 // first int is number of graphics, then each graphic, create in UserGraphicMap, derive Width & height from TPicture
3123 // & load into UserGraphicItem then store in UserGraphicVector
3124  UserGraphicVector.clear();
3125  TUserGraphicItem UGI;
3126  int NumberOfGraphics = Utilities->LoadFileInt(VecFile);
3127 
3128  for(int x = 0; x < NumberOfGraphics; x++)
3129  {
3130  UGI.FileName = GraphicsPath + "\\" + Utilities->LoadFileString(VecFile);
3131  UGI.HPos = Utilities->LoadFileInt(VecFile);
3132  UGI.VPos = Utilities->LoadFileInt(VecFile);
3133  UGI.Width = 0; // provisional value
3134  UGI.Height = 0; // provisional value
3135  UGI.UserGraphic = NULL; // provisional value
3136  UserGraphicVector.push_back(UGI);
3137  }
3138 // now load the map & set Width, Height & TPicture*
3139  bool FileError = false;
3140 
3141  for(int x = 0; x < NumberOfGraphics; x++)
3142  {
3143  if(FileError)
3144  {
3145  break; // otherwise keeps going round the loop
3146  }
3147  UGI = UserGraphicVectorAt(0, x);
3148  if(UserGraphicMap.empty()) // will be when x == 0 but not after
3149  {
3150  try
3151  {
3152 // TUserGraphicMapEntry UGME; //can't define it here, it has to be defined before it is used - now defined in TrackUnit.h
3153  UGME.first = UGI.FileName;
3154  UGME.second = new TPicture;
3155  UGME.second->LoadFromFile(UGME.first); // errors caught below
3156  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
3157  {
3158  throw Exception("Map Insertion Error 2 - UserGraphicMap insertion failure for " + UGI.FileName);
3159  }
3160  UGI.UserGraphic = UGME.second;
3161  UGI.Width = UGI.UserGraphic->Width;
3162  UGI.Height = UGI.UserGraphic->Height;
3163  UserGraphicVectorAt(1, x) = UGI;
3164  }
3165  catch(const EInvalidGraphic &e) //non error catch - CallLogPop called at end of function
3166  {
3167  //message already sent in CheckUserGraphics
3168  FileError = true;
3169  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3170  if(!UserGraphicMap.empty())
3171  {
3172  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3173  {
3174  delete UGMIt->second;
3175  }
3176  UserGraphicMap.clear();
3177  }
3178  }
3179  catch(const Exception &e) //non error catch - CallLogPop called at end of function
3180  {
3181  //message already sent in CheckUserGraphics
3182  FileError = true;
3183  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3184  if(!UserGraphicMap.empty())
3185  {
3186  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3187  {
3188  delete UGMIt->second;
3189  }
3190  UserGraphicMap.clear();
3191  }
3192  }
3193  }
3194  else
3195  {
3196  bool FoundInMap = false;
3197  for(TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3198  {
3199  if(UGI.FileName == UGMIt->first) // already exists in map
3200  {
3201  UGI.UserGraphic = UGMIt->second;
3202  UGI.Width = UGI.UserGraphic->Width;
3203  UGI.Height = UGI.UserGraphic->Height;
3204  UserGraphicVectorAt(2, x) = UGI;
3205  FoundInMap = true;
3206  break;
3207  }
3208  }
3209  if(!FoundInMap)
3210  {
3211  try
3212  {
3214  UGME.first = UGI.FileName;
3215  UGME.second = new TPicture;
3216  UGME.second->LoadFromFile(UGME.first); // errors caught below
3217  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
3218  {
3219  throw Exception("Map Insertion Error 3 - UserGraphicMap insertion failure for " + UGI.FileName);
3220  }
3221  UGI.UserGraphic = UGME.second;
3222  UGI.Width = UGI.UserGraphic->Width;
3223  UGI.Height = UGI.UserGraphic->Height;
3224  UserGraphicVectorAt(3, x) = UGI;
3225  }
3226  catch(const EInvalidGraphic &e) //non error catch - CallLogPop called at end of function
3227  {
3228  //message already sent in CheckUserGraphics
3229  FileError = true;
3230  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3231  if(!UserGraphicMap.empty())
3232  {
3233  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3234  {
3235  delete UGMIt->second;
3236  }
3237  UserGraphicMap.clear();
3238  }
3239  }
3240  catch(const Exception &e) //non error catch - CallLogPop called at end of function
3241  {
3242  //message already sent in CheckUserGraphics
3243  FileError = true;
3244  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3245  if(!UserGraphicMap.empty())
3246  {
3247  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3248  {
3249  delete UGMIt->second;
3250  }
3251  UserGraphicMap.clear();
3252  }
3253  }
3254  }
3255  }
3256  }
3257  Utilities->CallLogPop(2167);
3258 }
3259 
3260 // ---------------------------------------------------------------------------
3261 
3262 void TTrack::SaveTrack(int Caller, std::ofstream& VecFile, bool GraphicsFollow)
3263 {
3264 // VecFile already open and its pointer at right place on calling
3265 // if GraphicsFollow true, then save Marker as **Active elements**1
3266 // save trackfinished flag
3267  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveTrack, " + AnsiString(int(GraphicsFollow)));
3268  TTrackElement TrackElement, InactiveTrackElement;
3269 
3270 // save track elements
3271  Utilities->SaveFileInt(VecFile, TrackVector.size());
3272  if(GraphicsFollow)
3273  {
3274  VecFile << "**Active elements**1" << '\0' << '\n';
3275  }
3276  else
3277  {
3278  VecFile << "**Active elements**" << '\0' << '\n';
3279  }
3280  for(unsigned int x = 0; x < (TrackVector.size()); x++)
3281  {
3282  TrackElement = TrackElementAt(1092, x);
3283  VecFile << x << '\n'; // this is the TrackVectorNumber - extra, so easier to identify in the file
3284  VecFile << TrackElement.SpeedTag << '\n';
3285  VecFile << TrackElement.HLoc << '\n';
3286  VecFile << TrackElement.VLoc << '\n';
3287  if(TrackElement.TrackType == GapJump)
3288  {
3289  VecFile << TrackElement.ConnLinkPos[0] << '\n';
3290  VecFile << TrackElement.Conn[0] << '\n';
3291  }
3292  if((TrackElement.TrackType == SignalPost) || (TrackElement.TrackType == Points))
3293  {
3294  VecFile << TrackElement.Attribute << '\n';
3295  }
3296  if(TrackElement.TrackType == SignalPost)
3297  {
3298  if(TrackElement.CallingOnSet)
3299  {
3300  VecFile << int(1) << '\n';
3301  }
3302  else
3303  {
3304  VecFile << int(0) << '\n';
3305  }
3306  }
3307  VecFile << TrackElement.Length01 << '\n';
3308  VecFile << TrackElement.Length23 << '\n';
3309  VecFile << TrackElement.SpeedLimit01 << '\n';
3310  VecFile << TrackElement.SpeedLimit23 << '\n';
3311  VecFile << TrackElement.LocationName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3312  VecFile << TrackElement.ActiveTrackElementName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3313 // new for v0.6
3314  if(TrackElement.TrackType == SignalPost)
3315  {
3316  if(TrackElement.SigAspect == TTrackElement::ThreeAspect)
3317  {
3318  VecFile << "3*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3319  }
3320  else if(TrackElement.SigAspect == TTrackElement::TwoAspect)
3321  {
3322  VecFile << "2*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3323  }
3324  else if(TrackElement.SigAspect == TTrackElement::GroundSignal)
3325  {
3326  VecFile << "G*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3327  }
3328  else // 4 aspect
3329  {
3330  VecFile << "4*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3331  }
3332  }
3333  else
3334  {
3335  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3336  }
3337  }
3338 
3339  Utilities->SaveFileInt(VecFile, InactiveTrackVector.size());
3340  VecFile << "**Inactive elements**" << '\0' << '\n'; // extra
3341  for(unsigned int x = 0; x < (InactiveTrackVector.size()); x++)
3342  {
3343  InactiveTrackElement = InactiveTrackElementAt(136, x);
3344  VecFile << x << '\n'; // this is the Inactive TrackVectorNumber - extra
3345  VecFile << InactiveTrackElement.SpeedTag << '\n';
3346  VecFile << InactiveTrackElement.HLoc << '\n';
3347  VecFile << InactiveTrackElement.VLoc << '\n';
3348  VecFile << InactiveTrackElement.LocationName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3349  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3350  }
3351  Utilities->CallLogPop(449);
3352 }
3353 
3354 // ---------------------------------------------------------------------------
3355 
3356 bool TTrack::CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream& VecFile)
3357 {
3358 // VecFile already open and its pointer at right place on calling
3359 // check trackfinished flag
3360 // inactive elements follow immediately after active elements, no need to check for a marker between them
3361  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckTrackElementsInFile");
3362  int TempInt;
3363 
3364  GraphicsFollow = false;
3365  NumberOfActiveElements = Utilities->LoadFileInt(VecFile);
3366  if((NumberOfActiveElements < 0) || (NumberOfActiveElements > 1000000)) // No of active elements (up to 500 screens all completely full!)
3367  {
3368  Utilities->CallLogPop(1513);
3369  return(false);
3370  }
3371 // if(!Utilities->CheckAndCompareFileString(VecFile, "**Active elements**")) dropped at v2.4.0 as could have a '1' at the end if there are graphics
3372  AnsiString MarkerString;
3373 
3374  if(!Utilities->CheckAndReadFileString(VecFile, MarkerString)) // new version for v2.4.0
3375  {
3376  Utilities->CallLogPop(1758);
3377  return(false);
3378  }
3379  if(MarkerString[MarkerString.Length()] == '1')
3380  {
3381  GraphicsFollow = true;
3382  }
3383  for(int x = 0; x < NumberOfActiveElements; x++)
3384  {
3385  if(!Utilities->CheckFileInt(VecFile, x, x)) // TrackVectorNumber, must be 'x'
3386  {
3387  Utilities->CallLogPop(1759);
3388  return(false);
3389  }
3390  VecFile >> TempInt;
3391  int SpeedTag = TempInt;
3392  if((TempInt < 0) || (TempInt >= FirstUnusedSpeedTagNumber) || (TempInt == 17)) // Speedtag
3393  {
3394  Utilities->CallLogPop(1514);
3395  return(false);
3396  }
3397  VecFile >> TempInt;
3398  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // HLoc
3399  {
3400  Utilities->CallLogPop(1495);
3401  return(false);
3402  }
3403  VecFile >> TempInt;
3404  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // VLoc
3405  {
3406  Utilities->CallLogPop(1497);
3407  return(false);
3408  }
3409  if((SpeedTag > 87) && (SpeedTag < 96)) // GapJumps 88-95 incl
3410  {
3411  VecFile >> TempInt;
3412  if((TempInt < -1) || (TempInt > 3)) // ConnLinkPos[0]
3413  {
3414  Utilities->CallLogPop(1499);
3415  return(false);
3416  }
3417  VecFile >> TempInt;
3418  if((TempInt < -1) || (TempInt > 999999)) // Conn[0]
3419  {
3420  Utilities->CallLogPop(1500);
3421  return(false);
3422  }
3423  }
3424  if(((SpeedTag >= 7) && (SpeedTag <= 14)) || ((SpeedTag >= 28) && (SpeedTag <= 43)) || ((SpeedTag >= 132) && (SpeedTag <= 139)) ||
3425  ((SpeedTag >= 68) && (SpeedTag <= 75)))
3426  {
3427  VecFile >> TempInt;
3428  if((TempInt < -1) || (TempInt > 5)) // Points & signal attribute
3429  {
3430  Utilities->CallLogPop(1502);
3431  return(false);
3432  }
3433  }
3434  if((SpeedTag >= 68) && (SpeedTag <= 75)) // signals
3435  {
3436  VecFile >> TempInt;
3437  if((TempInt != 0) && (TempInt != 1)) // CallingOnSet
3438  {
3439  Utilities->CallLogPop(1155);
3440  return(false);
3441  }
3442  }
3443  VecFile >> TempInt;
3444  if((TempInt < -1) || (TempInt > 999999)) // Length01
3445  {
3446  Utilities->CallLogPop(1503);
3447  return(false);
3448  }
3449  VecFile >> TempInt;
3450  if((TempInt < -1) || (TempInt > 999999)) // Length23
3451  {
3452  Utilities->CallLogPop(1504);
3453  return(false);
3454  }
3455  VecFile >> TempInt;
3456  if((TempInt < -1) || (TempInt > 999999)) // SpeedLimit01
3457  {
3458  Utilities->CallLogPop(1505);
3459  return(false);
3460  }
3461  VecFile >> TempInt;
3462  if((TempInt < -1) || (TempInt > 999999)) // SpeedLimit23
3463  {
3464  Utilities->CallLogPop(1506);
3465  return(false);
3466  }
3467  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3468  {
3469  Utilities->CallLogPop(1142);
3470  return(false); // LocationName
3471  }
3472  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3473  {
3474  Utilities->CallLogPop(1143);
3475  return(false); // ActiveTrackElementName
3476  }
3477  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3478  {
3479  Utilities->CallLogPop(1787);
3480  return(false); // marker
3481  }
3482  }
3483  int NumberOfInactiveElements = 0;
3484 
3485  NumberOfInactiveElements = Utilities->LoadFileInt(VecFile);
3486  if(NumberOfInactiveElements < 0) // No of active elements
3487  {
3488  Utilities->CallLogPop(1493);
3489  return(false);
3490  }
3491  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3492  {
3493  Utilities->CallLogPop(1764);
3494  return(false); // **Inactive elements** marker
3495  }
3496  for(int x = 0; x < NumberOfInactiveElements; x++)
3497  {
3498  if(!Utilities->CheckFileInt(VecFile, x, x)) // TrackVectorNumber, must be 'x'
3499  {
3500  Utilities->CallLogPop(1765);
3501  return(false);
3502  }
3503  VecFile >> TempInt;
3504  if((TempInt < 0) || (TempInt >= FirstUnusedSpeedTagNumber) || (TempInt == 17)) // Speedtag
3505  {
3506  Utilities->CallLogPop(1494);
3507  return(false);
3508  }
3509  VecFile >> TempInt;
3510  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // HLoc
3511  {
3512  Utilities->CallLogPop(1496);
3513  return(false);
3514  }
3515  VecFile >> TempInt;
3516  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // VLoc
3517  {
3518  Utilities->CallLogPop(1498);
3519  return(false);
3520  }
3521  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3522  {
3523  Utilities->CallLogPop(1144);
3524  return(false); // LocationName
3525  }
3526  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3527  {
3528  Utilities->CallLogPop(1788);
3529  return(false); // marker
3530  }
3531  }
3532  Utilities->CallLogPop(1507);
3533  return(true);
3534 }
3535 
3536 // ---------------------------------------------------------------------------
3537 
3538 bool TTrack::CheckUserGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
3539 {
3540  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckUserGraphics");
3541  int NumberOfGraphics = Utilities->LoadFileInt(VecFile);
3542 
3543  if((NumberOfGraphics < 0) || (NumberOfGraphics > 100000)) // 100,000 should be plenty!
3544  {
3545  Utilities->CallLogPop(2168);
3546  return(false);
3547  }
3548  // filename in Graphics folder, then HPos, then VPos
3549  AnsiString FileName = "", TempStr = "";
3550 
3551  for(int x = 0; x < NumberOfGraphics; x++)
3552  {
3553  TPicture *TempPicture = new TPicture;
3554  try
3555  {
3556  if(!Utilities->CheckAndReadFileString(VecFile, FileName))
3557  {
3558  Utilities->CallLogPop(2169);
3559  delete TempPicture;
3560  return(false);
3561  }
3562  TempPicture->LoadFromFile(GraphicsPath + "\\" + FileName); // only loaded to check and catch errors
3563  delete TempPicture;
3564  if(!Utilities->CheckFileInt(VecFile, -2000000, 2000000)) // HPos, allow plenty of scope
3565  {
3566  Utilities->CallLogPop(2170);
3567  return(false);
3568  }
3569  if(!Utilities->CheckFileInt(VecFile, -2000000, 2000000)) // VPos
3570  {
3571  Utilities->CallLogPop(2171);
3572  return(false);
3573  }
3574  }
3575  catch(const EInvalidGraphic &e) //non error catch
3576  {
3577  //move file pointer to end of graphic section for later checks in session files
3578  Utilities->CheckAndReadFileString(VecFile, TempStr); //get rid of HPos
3579  Utilities->CheckAndReadFileString(VecFile, TempStr); //VPos
3580  for(int y = x + 1; y < NumberOfGraphics; y++)
3581  {
3582  Utilities->CheckAndReadFileString(VecFile, TempStr); //next FileName
3583  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3584  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3585  }
3586  ShowMessage(FileName +
3587  " has an incorrect file format, user graphics can't be loaded. Ensure that all user graphic files are valid with extension .bmp, .gif, .jpg, or .png");
3588  Utilities->CallLogPop(2172);
3589  delete TempPicture;
3590  return(true); //for these file errors allow railway or session to be loaded, changed at v2.6.0
3591  }
3592  catch(const Exception &e) //non error catch
3593  {
3594  //move file pointer to end of graphic section for later checks in session files
3595  Utilities->CheckAndReadFileString(VecFile, TempStr); //get rid of HPos
3596  Utilities->CheckAndReadFileString(VecFile, TempStr); //VPos
3597  for(int y = x + 1; y < NumberOfGraphics; y++)
3598  {
3599  Utilities->CheckAndReadFileString(VecFile, TempStr); //next FileName
3600  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3601  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3602  }
3603  ShowMessage("Unable to load user graphic files, ensure that " + FileName +
3604  " exists in the 'Graphics' folder and that it is has extension .bmp, .gif, .jpg, or .png.");
3605  Utilities->CallLogPop(2173);
3606  delete TempPicture;
3607  return(true); //for these file errors allow railway or session to be loaded, changed at v2.6.0
3608  }
3609  }
3610  Utilities->CallLogPop(2174);
3611  return(true);
3612 }
3613 
3614 // ---------------------------------------------------------------------------
3615 
3616 void TTrack::SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
3617 {
3618  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSessionBarriersDownVector");
3619  int VecSize = Track->BarriersDownVector.size();
3620 
3621  Utilities->SaveFileInt(OutFile, VecSize);
3622  for(int x = 0; x < VecSize; x++)
3623  {
3625  Utilities->SaveFileInt(OutFile, TALC.TypeOfRoute); //changed to int from bool in v2.6.0
3626  Utilities->SaveFileBool(OutFile, TALC.ReducedTimePenalty);
3627  Utilities->SaveFileInt(OutFile, (short)TALC.BarrierState);
3628  Utilities->SaveFileDouble(OutFile, TALC.ChangeDuration);
3629  Utilities->SaveFileInt(OutFile, TALC.BaseElementSpeedTag);
3630  Utilities->SaveFileInt(OutFile, TALC.HLoc);
3631  Utilities->SaveFileInt(OutFile, TALC.VLoc);
3632  Utilities->SaveFileDouble(OutFile, double(TALC.StartTime));
3633  }
3634  Utilities->CallLogPop(1963);
3635 }
3636 
3637 // ---------------------------------------------------------------------------
3638 
3639 void TTrack::SaveChangingLCVector(int Caller, std::ofstream &OutFile) //used only in errorfile
3640 {
3641  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveChangingLCVector");
3642  int VecSize = Track->ChangingLCVector.size();
3643 
3644  Utilities->SaveFileInt(OutFile, VecSize);
3645  for(int x = 0; x < VecSize; x++)
3646  {
3648  Utilities->SaveFileInt(OutFile, TALC.TypeOfRoute); //changed to int from bool in v2.6.0
3649  Utilities->SaveFileBool(OutFile, TALC.ReducedTimePenalty);
3650  Utilities->SaveFileInt(OutFile, (short)TALC.BarrierState);
3651  Utilities->SaveFileDouble(OutFile, TALC.ChangeDuration);
3652  Utilities->SaveFileInt(OutFile, TALC.BaseElementSpeedTag);
3653  Utilities->SaveFileInt(OutFile, TALC.HLoc);
3654  Utilities->SaveFileInt(OutFile, TALC.VLoc);
3655  Utilities->SaveFileDouble(OutFile, double(TALC.StartTime));
3656  }
3657  Utilities->CallLogPop(1980);
3658 }
3659 
3660 // ---------------------------------------------------------------------------
3661 
3662 bool TTrack::CheckActiveLCVector(int Caller, std::ifstream &VecFile)
3663 {
3664  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckActiveLCVector");
3665  int VecSize = Utilities->LoadFileInt(VecFile);
3666 
3667  for(int x = 0; x < VecSize; x++)
3668  {
3669  if(!Utilities->CheckFileInt(VecFile, 0, 2)) //changed from bool at v2.6.0 to allow TypeOfRoute == 2 for barriers manually lowered
3670  {
3671  Utilities->CallLogPop(1970);
3672  return(false);
3673  }
3674  if(!Utilities->CheckFileBool(VecFile))
3675  {
3676  Utilities->CallLogPop(1971);
3677  return(false);
3678  }
3679  if(!Utilities->CheckFileInt(VecFile, 0, 3))
3680  {
3681  Utilities->CallLogPop(1972);
3682  return(false);
3683  }
3684  if(!Utilities->CheckFileDouble(VecFile))
3685  {
3686  Utilities->CallLogPop(1973);
3687  return(false);
3688  }
3689  if(!Utilities->CheckFileInt(VecFile, 1, 2))
3690  {
3691  Utilities->CallLogPop(1974);
3692  return(false);
3693  }
3694  if(!Utilities->CheckFileInt(VecFile, -1000001, 999999))
3695  {
3696  Utilities->CallLogPop(1975);
3697  return(false);
3698  }
3699  if(!Utilities->CheckFileInt(VecFile, -1000001, 999999))
3700  {
3701  Utilities->CallLogPop(1976);
3702  return(false);
3703  }
3704  if(!Utilities->CheckFileDouble(VecFile))
3705  {
3706  Utilities->CallLogPop(1977);
3707  return(false);
3708  }
3709  }
3710  Utilities->CallLogPop(1978);
3711  return(true);
3712 }
3713 
3714 // ---------------------------------------------------------------------------
3715 
3716 void TTrack::LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
3717 {
3718  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadBarriersDownVector");
3719  int VecSize = Utilities->LoadFileInt(VecFile);
3720 
3721  for(int x = 0; x < VecSize; x++)
3722  {
3723  TActiveLevelCrossing TALC;
3724  TALC.TypeOfRoute = Utilities->LoadFileInt(VecFile); //changed to int from bool in v2.6.0
3725  TALC.ReducedTimePenalty = Utilities->LoadFileBool(VecFile);
3726  TALC.BarrierState = TBarrierState(Utilities->LoadFileInt(VecFile));
3727  TALC.ChangeDuration = Utilities->LoadFileDouble(VecFile);
3728  TALC.BaseElementSpeedTag = Utilities->LoadFileInt(VecFile);
3729  TALC.HLoc = Utilities->LoadFileInt(VecFile);
3730  TALC.VLoc = Utilities->LoadFileInt(VecFile);
3731  TALC.StartTime = TDateTime(Utilities->LoadFileDouble(VecFile));
3732  BarriersDownVector.push_back(TALC);
3733  }
3734  Utilities->CallLogPop(1979);
3735 }
3736 
3737 // ---------------------------------------------------------------------------
3738 
3739 void TTrack::RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
3740 /*
3741  Note, have to plot inactives before track because track has to overwrite NamedNonStationLocations, but, plot basic LC's (if flag set) after track
3742  so they lie above the track. Basic LCs are plotted for all but Level1Mode == OperMode (i.e. closed to trains), because the LC attributes will always be
3743  0 in such cases and because in OperMode the LCs have to be plotted again after the routes, which is done in Clearand....
3744 */
3745 {
3746  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildTrackAndText," + AnsiString((short)BothPointFilletsAndBasicLCs));
3747  TTrackElement Next;
3748 
3749 // Disp->ClearDisplay();
3751  while(ReturnNextInactiveTrackElement(0, Next))
3752  {
3753  if(Next.TrackType != LevelCrossing) // don't plot level crossings as these need to be plotted after the track
3754  {
3755  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3756  {
3757  // only plot if on screen, to save time
3758  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3760  {
3761  Next.PlotVariableTrackElement(2, Disp); // striped if not named
3762  }
3763  }
3764  }
3765  }
3766 
3767  TextHandler->RebuildFromTextVector(1, Disp); // plot text after inactives so can have text on stations etc
3768 
3769  NextTrackElementPtr = TrackVector.begin();
3770  while(ReturnNextTrackElement(0, Next))
3771  {
3772  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3773  {
3774  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3776  {
3777  if(Next.TrackType == Points)
3778  {
3779  PlotPoints(5, Next, Disp, BothPointFilletsAndBasicLCs);
3780  }
3781  else if(Next.TrackType == SignalPost)
3782  {
3783  PlotSignal(9, Next, Disp);
3784  }
3785  else if(Next.TrackType == GapJump)
3786  {
3787  PlotGap(0, Next, Disp);
3788  }
3789  else if(Next.TrackType == Continuation) //added for multiplayer graphic overlays
3790  {
3791  PlotContinuation(0, Next, Disp);
3792  }
3793  else
3794  {
3795  Next.PlotVariableTrackElement(3, Disp); // for footcrossings, may be striped or not
3796  }
3797  }
3798  }
3799  }
3800 
3801  if(BothPointFilletsAndBasicLCs)
3802  {
3804  while(ReturnNextInactiveTrackElement(4, Next))
3805  {
3806  if(Next.TrackType == LevelCrossing) // plot level crossings (if required) after the track
3807  {
3808  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3809  {
3810  // only plot if on screen, to save time, & OK as plotting one by one here
3811  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3813  {
3814  if(GetTrackElementFromTrackMap(1, Next.HLoc, Next.VLoc).SpeedTag == 1)
3815  {
3816  Disp->PlotOutput(193, (Next.HLoc * 16), (Next.VLoc * 16), RailGraphics->LCBothVer);
3817  }
3818  else
3819  {
3820  Disp->PlotOutput(194, (Next.HLoc * 16), (Next.VLoc * 16), RailGraphics->LCBothHor);
3821  }
3822  }
3823  }
3824  }
3825  }
3826  }
3827  Disp->Update();
3828  Utilities->CallLogPop(468);
3829 }
3830 
3831 // ---------------------------------------------------------------------------
3832 
3833 void TTrack::RebuildUserGraphics(int Caller, TDisplay *Disp) // new at v2.4.0
3834 {
3835  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildUserGraphics,");
3836  if(UserGraphicVector.empty())
3837  {
3838  Utilities->CallLogPop(2175);
3839  return;
3840  }
3841  TUserGraphicItem UGI;
3842 
3843  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
3844  {
3845  UGI = UserGraphicVectorAt(4, x);
3846  if(((UGI.HPos + UGI.Width - (Display->DisplayOffsetH * 16)) >= 0) && ((UGI.HPos - (Display->DisplayOffsetH * 16)) <
3847  (Utilities->ScreenElementWidth * 16)) && ((UGI.VPos + UGI.Height - (Display->DisplayOffsetV * 16)) >= 0) &&
3848  ((UGI.VPos - (Display->DisplayOffsetV * 16)) < (Utilities->ScreenElementHeight * 16)))
3849  {
3850  Disp->PlotAndAddUserGraphic(0, UGI);
3851  }
3852  }
3853  Disp->Update();
3854  Utilities->CallLogPop(2176);
3855 }
3856 
3857 // ---------------------------------------------------------------------------
3858 
3859 void TTrack::WriteTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap) //added text after inactives at v2.10.0
3860 /*
3861  Note, have to plot inactives before track because track has to overwrite 'name' platforms (NamedLocationElements)
3862 */
3863 {
3864  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteTrackAndTextToImage");
3865 // need to change graphics back to black on white if have a dark background
3866  TColor OldTransparentColour = Utilities->clTransparent;
3867 
3869  {
3870  Utilities->clTransparent = TColor(0xFFFFFF); // white
3873  }
3874  TTrackElement Next;
3875 
3876  Bitmap->Canvas->CopyMode = cmSrcCopy;
3878  Graphics::TBitmap *GraphicOutput;
3879 
3880  while(ReturnNextInactiveTrackElement(2, Next))
3881  {
3882  GraphicOutput = Next.GraphicPtr;
3883  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3884  {
3885  if(Next.LocationName == "") // plot as named or unnamed (striped)
3886  {
3887  // default is not striped
3888  switch(Next.SpeedTag)
3889  {
3890  case 76: // t platform
3891  GraphicOutput = RailGraphics->gl76Striped;
3892  break;
3893 
3894  case 77: // h platform
3895  GraphicOutput = RailGraphics->bm77Striped;
3896  break;
3897 
3898  case 78: // v platform
3899  GraphicOutput = RailGraphics->bm78Striped;
3900  break;
3901 
3902  case 79: // r platform
3903  GraphicOutput = RailGraphics->gl79Striped;
3904  break;
3905 
3906  case 96: // concourse
3907  GraphicOutput = RailGraphics->ConcourseStriped;
3908  break;
3909 
3910  case 129: // v footbridge
3911  GraphicOutput = RailGraphics->gl129Striped;
3912  break;
3913 
3914  case 130: // h footbridge
3915  GraphicOutput = RailGraphics->gl130Striped;
3916  break;
3917 
3918  case 131: // non-station named loc
3919  GraphicOutput = RailGraphics->bmNameStriped;
3920  break;
3921 
3922  case 145: // v underpass
3923  GraphicOutput = RailGraphics->gl145Striped;
3924  break;
3925 
3926  case 146: // h underpass
3927  GraphicOutput = RailGraphics->gl146Striped;
3928  break;
3929 
3930  default:
3931  GraphicOutput = Next.GraphicPtr;
3932  break;
3933  }
3934  }
3935  if(Next.SpeedTag == 144) // level crossing
3936  {
3937  if(GetTrackElementFromTrackMap(2, Next.HLoc, Next.VLoc).SpeedTag == 1)
3938  {
3939  GraphicOutput = RailGraphics->LCBothVer;
3940  }
3941  else
3942  {
3943  GraphicOutput = RailGraphics->LCBothHor;
3944  }
3945  }
3946  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), GraphicOutput);
3947  }
3948  }
3949 
3950  TextHandler->WriteTextToImage(0, Bitmap); //so overwrites inactive elements //added at v2.10.0
3951 
3952 
3953  NextTrackElementPtr = TrackVector.begin();
3954  while(ReturnNextTrackElement(2, Next))
3955  {
3956  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3957  {
3958  if(Next.TrackType == Points) // plot both fillets
3959  {
3960  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
3961  if(Next.SpeedTag < 28)
3962  {
3963  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3965  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3967  }
3968  else if(Next.SpeedTag < 132)
3969  {
3970  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3971  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 20][0]);
3972  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3973  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 20][1]);
3974  }
3975  else
3976  {
3977  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3978  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 108][0]);
3979  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3980  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 108][1]);
3981  }
3982  }
3983  else if(Next.TrackType == GapJump) // plot as connected or unconnected
3984  {
3985  if((Next.SpeedTag == 88) && (Next.Conn[0] > -1))
3986  {
3987  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88set);
3988  }
3989  else if((Next.SpeedTag == 88) && (Next.Conn[0] == -1))
3990  {
3991  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88unset);
3992  }
3993  if((Next.SpeedTag == 89) && (Next.Conn[0] > -1))
3994  {
3995  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89set);
3996  }
3997  else if((Next.SpeedTag == 89) && (Next.Conn[0] == -1))
3998  {
3999  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89unset);
4000  }
4001  if((Next.SpeedTag == 90) && (Next.Conn[0] > -1))
4002  {
4003  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90set);
4004  }
4005  else if((Next.SpeedTag == 90) && (Next.Conn[0] == -1))
4006  {
4007  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90unset);
4008  }
4009  if((Next.SpeedTag == 91) && (Next.Conn[0] > -1))
4010  {
4011  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91set);
4012  }
4013  else if((Next.SpeedTag == 91) && (Next.Conn[0] == -1))
4014  {
4015  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91unset);
4016  }
4017  if((Next.SpeedTag == 92) && (Next.Conn[0] > -1))
4018  {
4019  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92set);
4020  }
4021  else if((Next.SpeedTag == 92) && (Next.Conn[0] == -1))
4022  {
4023  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92unset);
4024  }
4025  if((Next.SpeedTag == 93) && (Next.Conn[0] > -1))
4026  {
4027  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93set);
4028  }
4029  else if((Next.SpeedTag == 93) && (Next.Conn[0] == -1))
4030  {
4031  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93unset);
4032  }
4033  if((Next.SpeedTag == 94) && (Next.Conn[0] > -1))
4034  {
4035  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94set);
4036  }
4037  else if((Next.SpeedTag == 94) && (Next.Conn[0] == -1))
4038  {
4039  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94unset);
4040  }
4041  if((Next.SpeedTag == 95) && (Next.Conn[0] > -1))
4042  {
4043  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95set);
4044  }
4045  else if((Next.SpeedTag == 95) && (Next.Conn[0] == -1))
4046  {
4047  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95unset);
4048  }
4049  }
4050  // below added for version 0.6, only stop signals to be drawn
4051  else if(Next.TrackType == SignalPost)
4052  {
4053  for(int x = 0; x < 40; x++)
4054  {
4055  if((SigTable[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == 0)) // need to plot as red regardless of actual attribute value
4056  {
4057  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
4058  // note these blanks plotted on lh signal side, even for rh signals, but works ok because the platform is replotted
4059  // in PlatformOnSignalSide, which return true for platform NOT on signal side for rh sigs
4060  int HOffset = 0;
4061  if(Next.SpeedTag > 73)
4062  {
4063  HOffset = 5;
4064  }
4065  else if(Next.SpeedTag == 71)
4066  {
4067  HOffset = 9;
4068  }
4069  int VOffset = 0;
4070  if(Next.SpeedTag == 69)
4071  {
4072  VOffset = 9;
4073  }
4074  else if(Next.SpeedTag == 72)
4075  {
4076  VOffset = 5;
4077  }
4078  else if(Next.SpeedTag == 74)
4079  {
4080  VOffset = 5;
4081  }
4082  Graphics::TBitmap *GraphicPtr;
4083  if(Next.SpeedTag > 71)
4084  {
4085  GraphicPtr = RailGraphics->bmDiagonalSignalBlank;
4086  }
4087  else if(Next.SpeedTag < 70)
4088  {
4089  GraphicPtr = RailGraphics->bmStraightNSSignalBlank;
4090  }
4091  else
4092  {
4093  GraphicPtr = RailGraphics->bmStraightEWSignalBlank;
4094  }
4095  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16) + HOffset, ((Next.VLoc - GetVLocMin()) * 16) + VOffset, GraphicPtr);
4096  // plot special signal platform if present
4097  Graphics::TBitmap* SignalPlatformGraphic;
4098  if(PlatformOnSignalSide(2, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic)) //
4099  {
4100  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4101  }
4102  // now plot signal (double yellow overwrites most of signal platform if present)
4103  // below amended for version 0.6
4105  {
4106  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableThreeAspect[x].SigPtr);
4107  }
4108  else if(Next.SigAspect == TTrackElement::TwoAspect)
4109  {
4110  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableTwoAspect[x].SigPtr);
4111  }
4112  else if(Next.SigAspect == TTrackElement::GroundSignal)
4113  {
4114  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4115  }
4116  else // 4 aspect
4117  {
4118  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTable[x].SigPtr);
4119  }
4120  break;
4121  }
4122  }
4123  }
4124  else
4125  {
4126  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4127  }
4128  }
4129  }
4130  if(OldTransparentColour != clB5G5R5)
4131  {
4132  Utilities->clTransparent = OldTransparentColour; // restore
4135  }
4136  Utilities->CallLogPop(1533);
4137 }
4138 
4139 // ---------------------------------------------------------------------------
4140 
4141 void TTrack::WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
4142 {
4143  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteGraphicsToImage");
4144  if(UserGraphicVector.empty())
4145  {
4146  Utilities->CallLogPop(2192);
4147  return;
4148  }
4149  else
4150  {
4151  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
4152  {
4153  Bitmap->Canvas->CopyMode = cmSrcCopy;
4154  Bitmap->Canvas->Draw(UserGraphicVectorAt(26, x).HPos - (GetHLocMin() * 16), UserGraphicVectorAt(27, x).VPos - (GetVLocMin() * 16),
4155  UserGraphicVectorAt(28, x).UserGraphic->Graphic);
4156  }
4157  }
4158  Utilities->CallLogPop(2193);
4159 }
4160 
4161 // ---------------------------------------------------------------------------
4162 
4163 void TTrack::WriteOperatingTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap)
4164 /*
4165  Note, have to plot inactives before track because track has to overwrite 'name' platforms (NamedLocationElements)
4166  Here plot all named elements as non-striped, points with active fillet, signals as they are set, and gaps as connected
4167 */
4168 {
4169  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteOperatingTrackAndTextToImage");
4170 // need to change graphics back to black on white if have a dark background
4171  TColor OldTransparentColour = Utilities->clTransparent;
4172 
4174  {
4175  Utilities->clTransparent = TColor(0xFFFFFF); // white
4178  }
4179  TTrackElement Next;
4180 
4181  Bitmap->Canvas->CopyMode = cmSrcCopy;
4183  Graphics::TBitmap *GraphicOutput;
4184 
4185  while(ReturnNextInactiveTrackElement(3, Next))
4186  {
4187  GraphicOutput = Next.GraphicPtr; // no striped name graphics
4188  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
4189  {
4190  if(Next.SpeedTag == 144) // level crossing
4191  {
4192  int BaseElement = GetTrackElementFromTrackMap(3, Next.HLoc, Next.VLoc).SpeedTag;
4193  if(BaseElement == 1) // hor element
4194  {
4195  if(Next.Attribute == 1) // open to trains
4196  {
4197  GraphicOutput = RailGraphics->LCBothHor;
4198  }
4199  else // plot as closed to trains if in any other state
4200  {
4201  GraphicOutput = RailGraphics->LCBothVer;
4202  }
4203  }
4204  else // vert element
4205  {
4206  if(Next.Attribute == 1) // open to trains
4207  {
4208  GraphicOutput = RailGraphics->LCBothVer;
4209  }
4210  else // plot as closed to trains if in any other state
4211  {
4212  GraphicOutput = RailGraphics->LCBothHor;
4213  }
4214  }
4215  }
4216  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), GraphicOutput);
4217  }
4218  }
4219 
4220  TextHandler->WriteTextToImage(1, Bitmap); //added at v2.10.0
4221 
4222  NextTrackElementPtr = TrackVector.begin();
4223  while(ReturnNextTrackElement(3, Next))
4224  {
4225  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
4226  {
4227  if(Next.TrackType == Points) // plot active fillet
4228  {
4229  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4230  if(Next.SpeedTag < 28)
4231  {
4232  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4234  }
4235  else if(Next.SpeedTag < 132)
4236  {
4237  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4239  }
4240  else
4241  {
4242  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4244  }
4245  }
4246  else if(Next.TrackType == GapJump) // plot as connected
4247  {
4248  if(Next.SpeedTag == 88)
4249  {
4250  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88set);
4251  }
4252  else if(Next.SpeedTag == 89)
4253  {
4254  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89set);
4255  }
4256  else if(Next.SpeedTag == 90)
4257  {
4258  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90set);
4259  }
4260  else if(Next.SpeedTag == 91)
4261  {
4262  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91set);
4263  }
4264  else if(Next.SpeedTag == 92)
4265  {
4266  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92set);
4267  }
4268  else if(Next.SpeedTag == 93)
4269  {
4270  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93set);
4271  }
4272  else if(Next.SpeedTag == 94)
4273  {
4274  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94set);
4275  }
4276  else if(Next.SpeedTag == 95)
4277  {
4278  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95set);
4279  }
4280  }
4281  else if(Next.TrackType == SignalPost) // plot in correct colour
4282  {
4283  for(int x = 0; x < 40; x++)
4284  {
4285  if((SigTable[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == Next.Attribute))
4286  {
4287  // plot blank first, then plot platform if present - (always not striped for operating railway)
4288  // note these blanks plotted on lh signal side, even for rh signals, but works ok because the platform is replotted
4289  // in PlatformOnSignalSide, which return true for platform NOT on signal side for rh sigs
4290  int HOffset = 0;
4291  if(Next.SpeedTag > 73)
4292  {
4293  HOffset = 5;
4294  }
4295  else if(Next.SpeedTag == 71)
4296  {
4297  HOffset = 9;
4298  }
4299  int VOffset = 0;
4300  if(Next.SpeedTag == 69)
4301  {
4302  VOffset = 9;
4303  }
4304  else if(Next.SpeedTag == 72)
4305  {
4306  VOffset = 5;
4307  }
4308  else if(Next.SpeedTag == 74)
4309  {
4310  VOffset = 5;
4311  }
4312  Graphics::TBitmap *GraphicPtr;
4313  if(Next.SpeedTag > 71)
4314  {
4315  GraphicPtr = RailGraphics->bmDiagonalSignalBlank;
4316  }
4317  else if(Next.SpeedTag < 70)
4318  {
4319  GraphicPtr = RailGraphics->bmStraightNSSignalBlank;
4320  }
4321  else
4322  {
4323  GraphicPtr = RailGraphics->bmStraightEWSignalBlank;
4324  }
4325  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16) + HOffset, ((Next.VLoc - GetVLocMin()) * 16) + VOffset, GraphicPtr);
4326  // plot special signal platform if present
4327  Graphics::TBitmap* SignalPlatformGraphic;
4328  if(PlatformOnSignalSide(1, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic))
4329  {
4330  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4331  }
4332  // now plot signal (double yellow overwrites most of signal platform if present)
4333  // below amended for version 0.6
4335  {
4336  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableThreeAspect[x].SigPtr);
4337  }
4338  else if(Next.SigAspect == TTrackElement::TwoAspect)
4339  {
4340  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableTwoAspect[x].SigPtr);
4341  }
4342  else if(Next.SigAspect == TTrackElement::GroundSignal)
4343  {
4344  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4345  }
4346  else // 4 aspect
4347  {
4348  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTable[x].SigPtr);
4349  }
4350  if((Next.CallingOnSet) && (Next.SigAspect != TTrackElement::GroundSignal))
4351  // normal signal calling on, need to add extra graphic, basic red signal plotted above from SigTable
4352  {
4353  if(Next.SpeedTag == 68)
4354  {
4355  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm68CallingOn);
4356  }
4357  if(Next.SpeedTag == 69)
4358  {
4359  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm69CallingOn);
4360  }
4361  if(Next.SpeedTag == 70)
4362  {
4363  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm70CallingOn);
4364  }
4365  if(Next.SpeedTag == 71)
4366  {
4367  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm71CallingOn);
4368  }
4369  if(Next.SpeedTag == 72)
4370  {
4371  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm72CallingOn);
4372  }
4373  if(Next.SpeedTag == 73)
4374  {
4375  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm73CallingOn);
4376  }
4377  if(Next.SpeedTag == 74)
4378  {
4379  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm74CallingOn);
4380  }
4381  if(Next.SpeedTag == 75)
4382  {
4383  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm75CallingOn);
4384  }
4385  }
4386  else if((Next.CallingOnSet) && (Next.SigAspect == TTrackElement::GroundSignal)) // ground signal calling on, use normal proceed aspect
4387  {
4388  for(int x = 0; x < 40; x++)
4389  {
4390  if((SigTableGroundSignal[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == 1)) // use attr 1 for proceed
4391  {
4392  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
4393  Display->PlotSignalBlankOnBitmap(Next.HLoc - GetHLocMin(), Next.VLoc - GetVLocMin(), Next.SpeedTag, Bitmap,
4394  Utilities->RHSignalFlag); // in case existing signal is a double yellow
4395  // plot special signal platform if present
4396  Graphics::TBitmap* SignalPlatformGraphic;
4397  if(PlatformOnSignalSide(4, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic))
4398  {
4399  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4400  }
4401  // now plot signal
4402  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4403  break;
4404  }
4405  }
4406  }
4407  break;
4408  }
4409  }
4410  }
4411  else
4412  {
4413  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4414  }
4415  }
4416  }
4417  if(OldTransparentColour != clB5G5R5)
4418  {
4419  Utilities->clTransparent = OldTransparentColour; // restore
4422  }
4423  Utilities->CallLogPop(1701);
4424 }
4425 
4426 // ---------------------------------------------------------------------------
4427 
4428 bool TTrack::FindAndHighlightAnUnsetGap(int Caller) // true if find one
4429 {
4430  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindAndHighlightAnUnsetGap");
4431  for(unsigned int x = 0; x < TrackVector.size(); x++)
4432  {
4433  if(TrackElementAt(1093, x).TrackType == GapJump)
4434  {
4435  if(TrackElementAt(1094, x).Conn[0] > -1)
4436  {
4437  continue; // to next 'x' value as this element has already been set
4438  }
4439  // here if identify a GapJump element not yet set
4440  GapPos = x;
4441  GapHLoc = TrackElementAt(1095, x).HLoc;
4442  GapVLoc = TrackElementAt(1096, x).VLoc;
4443  // highlight it
4445  Utilities->CallLogPop(469);
4446  return(true);
4447  }
4448  }
4449  Utilities->CallLogPop(470);
4450  return(false);
4451 }
4452 
4453 // ---------------------------------------------------------------------------
4454 
4455 bool TTrack::FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc) // true if find one
4456 {
4457  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindSetAndDisplayMatchingGap," + AnsiString(HLoc) + "," +
4458  AnsiString(VLoc));
4459  int Position;
4460  TTrackElement TrackElement;
4461 
4462  if(!(FindNonPlatformMatch(11, HLoc, VLoc, Position, TrackElement)))
4463  {
4464  Utilities->CallLogPop(471);
4465  return(false); // not found
4466  }
4467  if(TrackElement.TrackType != GapJump)
4468  {
4469  Utilities->CallLogPop(472);
4470  return(false); // found something but not a gap
4471  }
4472  if(Position == GapPos)
4473  {
4474  Utilities->CallLogPop(473);
4475  return(false); // selected original gap
4476  }
4477  if(TrackElementAt(1097, Position).Conn[0] != -1)
4478  {
4479  Utilities->CallLogPop(474);
4480  return(false); // already selected
4481  }
4482  TrackElementAt(1098, Position).Conn[0] = GapPos; // set Conn[0] at Position to GapPos & ConnLinkPos[0] to 0
4483  TrackElementAt(1099, Position).ConnLinkPos[0] = 0;
4484  TrackElementAt(1100, GapPos).Conn[0] = Position; // set other one similarly
4485  TrackElementAt(1101, GapPos).ConnLinkPos[0] = 0;
4486 // now highlight the selected location
4487  Display->Ellipse(0, HLoc * 16, VLoc * 16, clB0G5R0);
4488  Utilities->CallLogPop(475);
4489  return(true);
4490 }
4491 
4492 // ---------------------------------------------------------------------------
4493 
4494 bool TTrack::GapsUnset(int Caller)
4495 // returns true if there are gaps and any are unset
4496 {
4497  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GapsUnset");
4498  if(TrackVector.size() == 0)
4499  {
4500  Utilities->CallLogPop(476);
4501  return(false);
4502  }
4503  for(unsigned int x = 0; x < TrackVector.size(); x++)
4504  {
4505  if(TrackElementAt(1102, x).TrackType == GapJump)
4506  {
4507  if(TrackElementAt(1103, x).Conn[0] == -1) // unset if -1 (Gap always at position 0)
4508  {
4509  Utilities->CallLogPop(477);
4510  return(true);
4511  }
4512  else // set, but may not have matching element, or that element may not be set
4513  {
4514  if(TrackElementAt(1106, TrackElementAt(1107, x).Conn[0]).TrackType != GapJump)
4515  // check that the element pointed to by the gap link is a GapJump
4516  {
4517  ShowMessage("Error - gap connected to a non-gap. Railway file is corrupt, further use may cause a system crash");
4518  Utilities->CallLogPop(1137);
4519  return(false);
4520  }
4521 // here if gap connection is itself a GapJump
4522  if(TrackElementAt(1108, TrackElementAt(1109, x).Conn[0]).Conn[0] != (int)x)
4523  // check that the element pointed to by the gap link is a GapJump & that its gap link
4524  // points back to 'x'
4525  {
4526  Utilities->CallLogPop(478);
4527  return(true);
4528  }
4529 // here if gap connection itself points back to 'x' so these two GapJumps match properly
4530  }
4531  } // if(TrackElementAt(, x).TrackType == GapJump)
4532 
4533  } // for x...
4534  Utilities->CallLogPop(479);
4535  return(false);
4536 }
4537 
4538 // ---------------------------------------------------------------------------
4539 
4540 bool TTrack::NoGaps(int Caller) // returns true if there are no gaps
4541 {
4542  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoGaps");
4543  for(unsigned int x = 0; x < TrackVector.size(); x++)
4544  {
4545  if(TrackElementAt(1110, x).TrackType == GapJump)
4546  {
4547  Utilities->CallLogPop(1105);
4548  return(false);
4549  }
4550  }
4551  Utilities->CallLogPop(1106);
4552  return(true);
4553 }
4554 
4555 // ---------------------------------------------------------------------------
4556 
4557 bool TTrack::NoNamedLocationElements(int Caller) // returns true if there are no NamedLocationElements (includes footcrossings)
4558 {
4559  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoLocations");
4560  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
4561  {
4562  if(InactiveTrackElementAt(137, x).FixedNamedLocationElement)
4563  {
4564  Utilities->CallLogPop(1107);
4565  return(false);
4566  }
4567  }
4568  for(unsigned int x = 0; x < TrackVector.size(); x++)
4569  {
4570  if(TrackElementAt(1111, x).FixedNamedLocationElement)
4571  {
4572  Utilities->CallLogPop(1108);
4573  return(false);
4574  }
4575  }
4576  Utilities->CallLogPop(1109);
4577  return(true);
4578 }
4579 
4580 // ---------------------------------------------------------------------------
4581 
4583 // returns true if there are unnamed NamedLocationElements (includes footcrossings)
4584 // returns false otherwise or if there are no NamedLocationElements
4585 {
4586  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LocationsNotNamed");
4587  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
4588  {
4589  if(InactiveTrackElementAt(138, x).FixedNamedLocationElement)
4590  {
4591  if(InactiveTrackElementAt(139, x).LocationName == "")
4592  {
4593  Utilities->CallLogPop(1110);
4594  return(true);
4595  }
4596  }
4597  }
4598  for(unsigned int x = 0; x < TrackVector.size(); x++)
4599  {
4600  if(TrackElementAt(1112, x).FixedNamedLocationElement)
4601  {
4602  if(TrackElementAt(1113, x).LocationName == "")
4603  {
4604  Utilities->CallLogPop(1111);
4605  return(true);
4606  }
4607  }
4608  }
4609  Utilities->CallLogPop(1112);
4610  return(false);
4611 }
4612 
4613 // ---------------------------------------------------------------------------
4614 
4615 void TTrack::ShowSelectedGap(int Caller, TDisplay *Disp)
4616 {
4617  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ShowSelectedGap,");
4618  Disp->Ellipse(1, GapHLoc * 16, GapVLoc * 16, clB0G0R5);
4619  Utilities->CallLogPop(480);
4620 }
4621 
4622 // ---------------------------------------------------------------------------
4623 
4625 {
4626  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAnyNonMatchingGaps");
4627  if(TrackVector.size() == 0)
4628  {
4629  Utilities->CallLogPop(481);
4630  return;
4631  }
4632  for(unsigned int x = 0; x < TrackVector.size(); x++)
4633  {
4634  if(TrackElementAt(1114, x).TrackType == GapJump)
4635  {
4636  if(TrackElementAt(1115, x).Conn[0] > -1) // set
4637  {
4638  if(TrackElementAt(1116, TrackElementAt(1117, x).Conn[0]).TrackType != GapJump)
4639  // check that the element pointed to by the gap link is a GapJump & if not clear Conns & CLks
4640  {
4641  TrackElementAt(1118, x).Conn[0] = -1;
4642  TrackElementAt(1119, x).ConnLinkPos[0] = -1;
4643  continue; // to next 'x'
4644  }
4645 // here if gap connection is itself a GapJump
4646  if(TrackElementAt(1120, TrackElementAt(1349, x).Conn[0]).Conn[0] != (int)x)
4647  // check that the element pointed to by the gap link is a GapJump & that its gap link points back to 'x'
4648  // if not clear Conns & CLks
4649  {
4650  TrackElementAt(1121, x).Conn[0] = -1;
4651  TrackElementAt(1122, x).ConnLinkPos[0] = -1;
4652  continue; // to next 'x'
4653  }
4654 // here if gap connection itself points back to 'x' so these two GapJumps match properly
4655 // hence no more action needed on these Conns & CLks
4656  }
4657  } // else //gap jump
4658 
4659  } // for x...
4660 // throw Exception("Test Exception");//test
4661  Utilities->CallLogPop(482);
4662 }
4663 
4664 // ---------------------------------------------------------------------------
4665 
4666 void TTrack::ResetSignals(int Caller)
4667 {
4668  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetSignals");
4669  for(unsigned int x = 0; x < TrackVector.size(); x++)
4670  {
4671  if(TrackElementAt(1123, x).TrackType == SignalPost)
4672  {
4673  TrackElementAt(1124, x).Attribute = 0;
4674  }
4675  }
4676  Utilities->CallLogPop(483);
4677 }
4678 
4679 // ---------------------------------------------------------------------------
4680 
4681 void TTrack::ResetPoints(int Caller)
4682 {
4683  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetPoints");
4684  for(unsigned int x = 0; x < TrackVector.size(); x++)
4685  {
4686  if(TrackElementAt(1125, x).TrackType == Points)
4687  {
4688  TrackElementAt(1126, x).Attribute = 0;
4689  }
4690  }
4691  Utilities->CallLogPop(484);
4692 }
4693 
4694 // ---------------------------------------------------------------------------
4695 
4696 bool TTrack::RepositionAndMapTrack(int Caller) // doesn't involve InactiveTrack
4697 {
4698  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RepositionAndMapTrack");
4699  if(TrackVector.empty())
4700  {
4701  TrackMap.clear();
4702  Utilities->CallLogPop(485);
4703  return(true);
4704  }
4705 // build new vector from map (map already in ascending order of locations & no erase elements in map)
4706  THVPair TrackMapKeyPair;
4707 
4708  NewVector.clear();
4709  TTrackMapIterator TrackMapPtr;
4710 
4711  if(!TrackMap.empty())
4712  {
4713  for(TrackMapPtr = TrackMap.begin(); TrackMapPtr != TrackMap.end(); TrackMapPtr++)
4714  {
4715  NewVector.push_back(TrackElementAt(6, TrackMapPtr->second));
4716  }
4717  }
4718  if(NewVector.size() != TrackMap.size())
4719  {
4720  throw Exception("Error - Map & Vector different sizes");
4721  }
4722  unsigned int NonZeroCount = 0;
4723 
4724  for(unsigned int x = 0; x < TrackVector.size(); x++)
4725  {
4726  if(TrackElementAt(1127, x).TrackType != Erase)
4727  {
4728  NonZeroCount++;
4729  }
4730  }
4731  if(NewVector.size() != NonZeroCount)
4732  {
4733  throw Exception("Error - NewVector & NonZero TrackVector different sizes");
4734  }
4736  TrackMap.clear(); // ready to rebuild map after repositioning of TrackVector elements
4737  TTrackMapEntry TrackMapEntry;
4738 
4739  for(unsigned int x = 0; x < TrackVector.size(); x++)
4740  {
4741  TrackMapKeyPair.first = TrackElementAt(1128, x).HLoc;
4742  TrackMapKeyPair.second = TrackElementAt(1129, x).VLoc;
4743  TrackMapEntry.first = TrackMapKeyPair;
4744  TrackMapEntry.second = x;
4745  if(!(TrackMap.insert(TrackMapEntry).second))
4746  {
4747  throw Exception("Error - map insertion failure, TrackVector in error");
4748  }
4749  }
4750 // All track now relocated in TrackVector, reset all Conns & CLks
4751  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4752  {
4753  for(unsigned int y = 0; y < 4; y++)
4754  {
4755  TrackElementAt(1130, x).Conn[y] = -1;
4756  TrackElementAt(1131, x).ConnLinkPos[y] = -1;
4757  }
4758  }
4759  RebuildLocationNameMultiMap(1); // to ensure all position entries correct after track vector changes
4760  CheckMapAndTrack(4); // test
4761  CheckMapAndInactiveTrack(4); // test
4762  CheckLocationNameMultiMap(8); // test
4763  if(!ResetGapsFromGapMap(1))
4764  {
4765  Utilities->CallLogPop(489);
4766  return(false);
4767  }
4768  Utilities->CallLogPop(490);
4769  return(true);
4770 }
4771 
4772 // ---------------------------------------------------------------------------
4773 
4774 void TTrack::BuildGapMapFromTrackVector(int Caller) // Map contains one entry for each pair of matched gaps
4775 {
4776  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BuildGapMapFromTrackVector");
4777  GapMap.clear();
4778  THVPair GapMapKeyPair, GapMapValuePair;
4779  TGapMapEntry GapMapEntry;
4780 
4781  for(unsigned int x = 0; x < TrackVector.size(); x++)
4782  {
4783  if(TrackElementAt(1132, x).TrackType == GapJump)
4784  {
4785  GapMapKeyPair.first = TrackElementAt(1133, x).HLoc;
4786  GapMapKeyPair.second = TrackElementAt(1134, x).VLoc;
4787  GapMapEntry.first = GapMapKeyPair;
4788  if(TrackElementAt(1135, x).Conn[0] == -1)
4789  {
4790  throw Exception("Error - Gap connection == -1 Can't build GapMap");
4791  }
4792  GapMapValuePair.first = TrackElementAt(7, TrackElementAt(1136, x).Conn[0]).HLoc;
4793  GapMapValuePair.second = TrackElementAt(8, TrackElementAt(1137, x).Conn[0]).VLoc;
4794  GapMapEntry.second = GapMapValuePair;
4795  if(GapMap.find(GapMapValuePair) == GapMap.end()) // if ValuePair already included as a key then result won't be end()
4796  {
4797  GapMap.insert(GapMapEntry);
4798  }
4799  }
4800  }
4801  Utilities->CallLogPop(492);
4802 }
4803 
4804 // ---------------------------------------------------------------------------
4805 
4806 bool TTrack::LinkTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool FinalCall)
4807 {
4808  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LinkTrack," + AnsiString((short)FinalCall));
4809 
4810 //1st pass to check track element locations - split into 2 passes at v2.11.1 so positioning checked before linkages, requested by Dan(#4669) 18/12/21 via Discord
4811  LocError = false;
4812  bool TrackElementPositionsOK = true;
4813 
4814  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4815  {
4816  if(TrackElementAt(1138, x).TrackType == Erase) //Erase isn't used any more as a track type
4817  {
4818  continue; // skip blank elements
4819  }
4820 // check footcrossing linkages
4821  if(TrackElementAt(1139, x).TrackType == FootCrossing)
4822  {
4823  if(!CheckFootCrossingLinks(1, TrackElementAt(1140, x)))
4824  {
4825  ShowMessage(
4826  "Footbridge or underpass connection error. Each end must connect to a platform, concourse "
4827  "or other footbridge or underpass, and they can't connect to each other (i.e. a footbridge "
4828  "can't connect to an underpass or vice versa)");
4829  HLoc = TrackElementAt(1141, x).HLoc;
4830  VLoc = TrackElementAt(1142, x).VLoc;
4831  LocError = true;
4832  Utilities->CallLogPop(493);
4833  return(false);
4834  }
4835  }
4836  for(unsigned int y = 0; y < 4; y++) // check all links for each element
4837  {
4838  if(TrackElementAt(1143, x).Link[y] <= 0)
4839  {
4840  continue; // no link
4841  }
4842  if((TrackElementAt(1144, x).TrackType == Buffers) && (TrackElementAt(1145, x).Config[y] == End))
4843  {
4844  continue; // buffer
4845  }
4846  if(TrackElementAt(1146, x).Config[y] == Gap)
4847  {
4848  continue; // gaps set later from GapMap
4849  }
4850  // get required H & V for track element joining link 'y'
4851  int NewHLoc = TrackElementAt(1437, x).HLoc + LinkHVArray[TrackElementAt(1148, x).Link[y]][0];
4852  int NewVLoc = TrackElementAt(1438, x).VLoc + LinkHVArray[TrackElementAt(1150, x).Link[y]][1];
4853  // find track element if present
4854  bool ConnectionFoundFlag;
4855  int VecPos = GetVectorPositionFromTrackMap(14, NewHLoc, NewVLoc, ConnectionFoundFlag);
4856  if((TrackElementAt(1151, x).TrackType == Continuation) && (y == 0) && ConnectionFoundFlag)
4857  {
4858  ShowMessage("Can't have a track element adjacent to a continuation exit");
4859  HLoc = TrackElementAt(1152, x).HLoc;
4860  VLoc = TrackElementAt(1153, x).VLoc;
4861  LocError = true;
4862  if(FinalCall)
4863  {
4864  throw Exception("Error in final track linkage - continuation adjacent to another element");
4865  }
4866  Utilities->CallLogPop(1539);
4867  return(false);
4868  }
4869  if((TrackElementAt(1154, x).TrackType == Continuation) && (TrackElementAt(1155, x).Config[y] == End))
4870  {
4871  continue;
4872  }
4873  if(ConnectionFoundFlag)
4874  {
4875  TrackElementAt(1156, x).Conn[y] = VecPos; //<-- this sets the Conn value
4876  // find connecting link in the newly found track element if there is one & make buffer & adjacent signals check
4877  if((TrackElementAt(1157, x).Config[1 - y] == Signal) && IsLCAtHV(50, TrackElementAt(1158, VecPos).HLoc, TrackElementAt(1350, VecPos).VLoc))
4878  {
4879  // new in v2.4.0 - Krizar (Kristian Zarebski) found this error
4880  ShowMessage("Can't have an exit signal next to a level crossing - it can cause the train to foul the crossing in some circumstances");
4881  // otherwise when single route element removed in front of train the LC will start to close and the train will crash
4882  TrackElementPositionsOK = false;
4883  }
4884  else if(((TrackElementAt(1159, x).TrackType == Points) || (TrackElementAt(1160, x).TrackType == SignalPost) || (TrackElementAt(1161, x).TrackType == Crossover))
4885  && (TrackElementAt(1162, VecPos).TrackType == Buffers))
4886  {
4887  ShowMessage("Can't have points, crossover or signal next to buffers - need room for a train without fouling");
4888  // need room for a train (2 elements) without fouling points or signals
4889  TrackElementPositionsOK = false;
4890  }
4891  else if(((TrackElementAt(1163, x).TrackType == Points) || (TrackElementAt(1164, x).TrackType == SignalPost) || (TrackElementAt(1165, x).TrackType == Crossover) ||
4892  (TrackElementAt(1166, x).TrackType == Bridge)) && (TrackElementAt(1167, VecPos).TrackType == Continuation))
4893  {
4894  ShowMessage("Can't have points, crossover, bridge or signal next to a continuation - it can cause route setting problems");
4895  // route setting won't allow an end of route selection adjacent to an existing route, which would happen
4896  // if continuation next to a signal; also none of these can be a named location, and a continuation can
4897  // be named but needs the adjacent element named too
4898  TrackElementPositionsOK = false;
4899  }
4900  else if((TrackElementAt(1168, x).TrackType == SignalPost) && (TrackElementAt(1169, VecPos).TrackType == SignalPost) &&
4901  (TrackElementAt(1170, x).SpeedTag == TrackElementAt(1171, VecPos).SpeedTag))
4902  {
4903  ShowMessage("Can't have two same-direction signals adjacent to each other as there is no room for a train between them");
4904  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
4905  // selected - appears as trying to select a signal that is not the next in line from the starting signal
4906  TrackElementPositionsOK = false;
4907  }
4908  else if((TrackElementAt(1172, x).Config[y] == Signal) && (TrackElementAt(1173, VecPos).TrackType == Bridge) && !OverrideAndHideSignalBridgeMessage)
4909  {
4910  ShowMessage("Signal facing a bridge - routes can't be truncated to this or other such signals.\n\nThis restriction can be removed or reinstated by pressing\nCTRL ALT 5. When removed this message will not be shown again.");
4911  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
4912  // selected - appears as trying to select a signal that is not the next in line from the starting signal
4913  TrackElementPositionsOK = false;
4914  }
4915  else if(IsLCAtHV(45, TrackElementAt(1174, x).HLoc, TrackElementAt(1175, x).VLoc) && IsLCAtHV(46, TrackElementAt(1176, VecPos).HLoc, TrackElementAt(1177, VecPos).VLoc))
4916  // true if a level crossing is present at both x and VecPos - can't have two adjacent level crossings on the same track
4917  {
4918  ShowMessage("Can't have two level crossings adjacent to each other on the same track");
4919  TrackElementPositionsOK = false;
4920  }
4921  // if failed then set the invert values for the offending element
4922  if(!TrackElementPositionsOK)
4923  {
4924  HLoc = TrackElementAt(1183, x).HLoc;
4925  VLoc = TrackElementAt(1184, x).VLoc;
4926  LocError = true;
4927  if(FinalCall)
4928  {
4929  throw Exception("Error in track element positions in FinalCall");
4930  }
4931  Utilities->CallLogPop(494);
4932  return(false);
4933  }
4934  }
4935  // no 'else' here, if there's no link then will be picked up in 2nd pass
4936  }
4937  } // for(unsigned int x=0;x<TrackVector.size();x++)
4938 
4939 
4940 //2nd pass - looking for missing connections
4941  LocError = false;
4942  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4943  {
4944  if(TrackElementAt(1439, x).TrackType == Erase) //Erase isn't used any more as a track type
4945  {
4946  continue; // skip blank elements
4947  }
4948  for(unsigned int y = 0; y < 4; y++) // check all links for each element
4949  {
4950  if(TrackElementAt(1440, x).Link[y] <= 0)
4951  {
4952  continue; // no link
4953  }
4954  if((TrackElementAt(1441, x).TrackType == Buffers) && (TrackElementAt(1442, x).Config[y] == End))
4955  {
4956  continue; // buffer
4957  }
4958  if(TrackElementAt(1443, x).Config[y] == Gap)
4959  {
4960  continue; // gaps set later from GapMap
4961  }
4962  if((TrackElementAt(1444, x).TrackType == Continuation) && (TrackElementAt(1445, x).Config[y] == End))
4963  {
4964  continue; //continuation
4965  }
4966  // get required H & V for track element joining link 'y'
4967  int NewHLoc = TrackElementAt(1147, x).HLoc + LinkHVArray[TrackElementAt(1448, x).Link[y]][0];
4968  int NewVLoc = TrackElementAt(1149, x).VLoc + LinkHVArray[TrackElementAt(1449, x).Link[y]][1];
4969  // find track element if present
4970  bool ConnectionFoundFlag;
4971  bool LinkMatchFound = false;
4972  int VecPos = GetVectorPositionFromTrackMap(66, NewHLoc, NewVLoc, ConnectionFoundFlag);
4973  // if there isn't a connection set the invert values for the offending element
4974  if(ConnectionFoundFlag) //set the ConnLinkPos values
4975  {
4976  for(unsigned int a = 0; a < 4; a++)
4977  {
4978  if((TrackElementAt(1178, VecPos).Link[a] == (10 - TrackElementAt(1179, x).Link[y])) && (TrackElementAt(1180, VecPos).Config[a] != End) &&
4979  (TrackElementAt(1181, VecPos).Config[a] != Gap))
4980  {
4981  TrackElementAt(1182, x).ConnLinkPos[y] = a;
4982  // note - this ensures that if the connecting element is a leading point
4983  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
4984  // (Points have the same link value for both [0] and [2])
4985  LinkMatchFound = true;
4986  break; // stop after first find or will find later link for leading point
4987  }
4988  }
4989  if(!LinkMatchFound)
4990  {
4991  HLoc = TrackElementAt(1446, x).HLoc;
4992  VLoc = TrackElementAt(1447, x).VLoc;
4993  LocError = true;
4994  if(FinalCall)
4995  {
4996  throw Exception("Error in final track linkage - - no matching link found");
4997  }
4998  Utilities->CallLogPop(495);
4999  return(false);
5000  }
5001  }
5002  else //error
5003  {
5004  HLoc = TrackElementAt(1185, x).HLoc;
5005  VLoc = TrackElementAt(1186, x).VLoc;
5006  LocError = true;
5007  if(FinalCall)
5008  {
5009  throw Exception("Error in final track linkage - connection not found");
5010  }
5011  Utilities->CallLogPop(2443);
5012  return(false);
5013  }
5014  }
5015  }
5016 //end of 2nd pass
5017 
5018  if(FinalCall)
5019  {
5021  }
5022 
5023 // confirmatiory checks that all ok - or throw error
5024  bool ConnErrorFlag = false;
5025 
5026  for(unsigned int x = 0; x < TrackVector.size(); x++)
5027  {
5028  if((TrackElementAt(1187, x).Link[0] > 0) && (TrackElementAt(1188, x).Config[0] != End) && (TrackElementAt(1189, x).Conn[0] == -1))
5029  {
5030  ConnErrorFlag = true;
5031  }
5032  if((TrackElementAt(1190, x).Link[1] > 0) && (TrackElementAt(1191, x).Config[1] != End) && (TrackElementAt(1192, x).Conn[1] == -1))
5033  {
5034  ConnErrorFlag = true;
5035  }
5036  if((TrackElementAt(1193, x).Link[2] > 0) && (TrackElementAt(1194, x).Config[2] != End) && (TrackElementAt(1195, x).Conn[2] == -1))
5037  {
5038  ConnErrorFlag = true;
5039  }
5040  if((TrackElementAt(1196, x).Link[3] > 0) && (TrackElementAt(1197, x).Config[3] != End) && (TrackElementAt(1198, x).Conn[3] == -1))
5041  {
5042  ConnErrorFlag = true;
5043  }
5044  if(FinalCall) // StationStopLinks only set during FinalCall so only check at FinalCall
5045  {
5046  if(TrackElementAt(1199, x).ActiveTrackElementName == "")
5047  {
5048  if((TrackElementAt(1200, x).StationEntryStopLinkPos1 != -1) || (TrackElementAt(1201, x).StationEntryStopLinkPos2 != -1))
5049  {
5050  throw Exception("Error, StationEntryStopLinkPos not -1 for unnamed element at TrackVectorPosition = " + AnsiString(x));
5051  }
5052  }
5053  }
5054  }
5055  if(ConnErrorFlag)
5056  {
5057  if(FinalCall)
5058  {
5059  throw Exception("ConnError in LinkTrack - Final");
5060  }
5061  else
5062  {
5063  throw Exception("ConnError in LinkTrack - Precheck");
5064  }
5065  }
5066  bool CLkErrorFlag = false;
5067 
5068  for(unsigned int x = 0; x < TrackVector.size(); x++)
5069  {
5070  if((TrackElementAt(1202, x).Link[0] > 0) && (TrackElementAt(1203, x).Config[0] != End) && (TrackElementAt(1204, x).ConnLinkPos[0] == -1))
5071  {
5072  CLkErrorFlag = true;
5073  }
5074  if((TrackElementAt(1205, x).Link[1] > 0) && (TrackElementAt(1206, x).Config[1] != End) && (TrackElementAt(1207, x).ConnLinkPos[1] == -1))
5075  {
5076  CLkErrorFlag = true;
5077  }
5078  if((TrackElementAt(1208, x).Link[2] > 0) && (TrackElementAt(1209, x).Config[2] != End) && (TrackElementAt(1210, x).ConnLinkPos[2] == -1))
5079  {
5080  CLkErrorFlag = true;
5081  }
5082  if((TrackElementAt(1211, x).Link[3] > 0) && (TrackElementAt(1212, x).Config[3] != End) && (TrackElementAt(1213, x).ConnLinkPos[3] == -1))
5083  {
5084  CLkErrorFlag = true;
5085  }
5086  }
5087 
5088  if(CLkErrorFlag)
5089  {
5090  if(FinalCall)
5091  {
5092  throw Exception("CLkError in LinkTrack - Final");
5093  }
5094  else
5095  {
5096  throw Exception("CLkError in LinkTrack - Precheck");
5097  }
5098  }
5099 
5100 // set element lengths to min of 10m
5101  for(unsigned int x = 0; x < TrackVector.size(); x++)
5102  {
5103  if(TrackElementAt(1214, x).TrackType == Erase)
5104  {
5105  continue; // skip blank elements
5106  }
5107  if((TrackElementAt(1215, x).Length01 < 10) && (TrackElementAt(1435, x).Length01 != -1))
5108  {
5109  TrackElementAt(1216, x).Length01 = 10;
5110  }
5111  if((TrackElementAt(1217, x).Length23 < 10) && (TrackElementAt(1218, x).Length23 != -1))
5112  {
5113  TrackElementAt(1219, x).Length23 = 10;
5114  }
5115  }
5116 
5117  if(FinalCall) // ONLY at FinalCall, no point calling twice
5118  {
5119  CalcHLocMinEtc(3);
5120  }
5121 
5122  Utilities->CallLogPop(497);
5123  return(true);
5124 }
5125 
5126 // ---------------------------------------------------------------------------
5127 
5128 bool TTrack::LinkTrackNoMessages(int Caller, bool FinalCall)
5129 {
5130  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LinkTrackNoMessages," + AnsiString((short)FinalCall));
5131  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
5132  {
5133  if(TrackElementAt(1220, x).TrackType == Erase)
5134  {
5135  continue; // skip blank elements
5136 
5137  }
5138 // check footcrossing linkages
5139  if(TrackElementAt(1221, x).TrackType == FootCrossing)
5140  {
5141  if(!CheckFootCrossingLinks(3, TrackElementAt(1222, x)))
5142  {
5143  Utilities->CallLogPop(1127);
5144  return(false);
5145  }
5146  }
5147  for(unsigned int y = 0; y < 4; y++) // check all links for each element
5148  {
5149  if(TrackElementAt(1223, x).Link[y] <= 0)
5150  {
5151  continue; // no link
5152  }
5153  if((TrackElementAt(1224, x).TrackType == Buffers) && (TrackElementAt(1225, x).Config[y] == End))
5154  {
5155  continue; // buffer
5156  }
5157  if(TrackElementAt(1226, x).Config[y] == Gap)
5158  {
5159  continue; // gaps set later from GapMap
5160 
5161  }
5162  // get required H & V for track element joining link 'y'
5163  int NewHLoc = TrackElementAt(1227, x).HLoc + LinkHVArray[TrackElementAt(1228, x).Link[y]][0];
5164  int NewVLoc = TrackElementAt(1229, x).VLoc + LinkHVArray[TrackElementAt(1230, x).Link[y]][1];
5165  // find track element if present
5166  bool ConnectionFoundFlag;
5167  int VecPos = GetVectorPositionFromTrackMap(38, NewHLoc, NewVLoc, ConnectionFoundFlag);
5168  if((TrackElementAt(1231, x).TrackType == Continuation) && (y == 0) && ConnectionFoundFlag)
5169  {
5170  if(FinalCall)
5171  {
5172  throw Exception("Error in final track linkage - continuation adjacent to another element");
5173  }
5174  Utilities->CallLogPop(1540);
5175  return(false);
5176  }
5177  if((TrackElementAt(1232, x).TrackType == Continuation) && (TrackElementAt(1233, x).Config[y] == End))
5178  {
5179  continue;
5180  }
5181  if(ConnectionFoundFlag)
5182  {
5183  TrackElementAt(1234, x).Conn[y] = VecPos;
5184  bool LinkFoundFlag = false;
5185  // find connecting link in the newly found track element if there is one & make checks
5186  if(((TrackElementAt(1235, x).TrackType == Points) || (TrackElementAt(1236, x).TrackType == SignalPost) || (TrackElementAt(1237, x).TrackType == Crossover)) &&
5187  (TrackElementAt(1238, VecPos).TrackType == Buffers))
5188  {
5189  Utilities->CallLogPop(1541);
5190  return(false);
5191  }
5192  else if(((TrackElementAt(1239, x).TrackType == Points) || (TrackElementAt(1240, x).TrackType == SignalPost) || (TrackElementAt(1241, x).TrackType == Crossover) ||
5193  (TrackElementAt(1242, x).TrackType == Bridge)) && (TrackElementAt(1243, VecPos).TrackType == Continuation))
5194  {
5195  Utilities->CallLogPop(1542);
5196  return(false);
5197  }
5198  else if((TrackElementAt(1244, x).TrackType == SignalPost) && (TrackElementAt(1245, VecPos).TrackType == SignalPost) &&
5199  (TrackElementAt(1246, x).SpeedTag == TrackElementAt(1247, VecPos).SpeedTag))
5200  {
5201  Utilities->CallLogPop(1543);
5202  return(false);
5203  }
5204  else if(IsLCAtHV(47, TrackElementAt(1248, x).HLoc, TrackElementAt(1249, x).VLoc) && IsLCAtHV(48, TrackElementAt(1250, VecPos).HLoc, TrackElementAt(1251, VecPos).VLoc))
5205  // true if a level crossing is present at both x and VecPos - can't have two adjacent level crossings on the same track
5206  {
5207  Utilities->CallLogPop(1981);
5208  return(false);
5209  }
5210 /* remove this restriction now that not permitted to treat a named continuation as a location stop
5211  else if(TrackElementAt(, x).TrackType == Continuation)
5212  {
5213  int H = TrackElementAt(, x).HLoc;
5214  int V = TrackElementAt(, x).VLoc;
5215  bool FoundFlag = false;
5216  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(18, H, V, FoundFlag);
5217  if(FoundFlag)
5218  {
5219  if(InactiveTrackElementAt(93, IMPair.first).TrackType == NamedNonStationLocation)
5220  {
5221  int NewH = TrackElementAt(, (TrackElementAt(, x).Conn[1])).HLoc;
5222  int NewV = TrackElementAt(, (TrackElementAt(, x).Conn[1])).VLoc;
5223  TIMPair NewIMPair = GetVectorPositionsFromInactiveTrackMap(19, NewH, NewV, FoundFlag);
5224  if(FoundFlag)
5225  {
5226  if(InactiveTrackElementAt(94, NewIMPair.first).TrackType != NamedNonStationLocation)
5227  {
5228  Utilities->CallLogPop();
5229  return false;
5230  }
5231  }
5232  else
5233  {
5234  Utilities->CallLogPop();
5235  return false;
5236  }
5237  }
5238  }
5239  }
5240 */
5241  for(unsigned int a = 0; a < 4; a++)
5242  {
5243  if((TrackElementAt(1252, VecPos).Link[a] == (10 - TrackElementAt(1253, x).Link[y])) && (TrackElementAt(1254, VecPos).Config[a] != End) &&
5244  (TrackElementAt(1255, VecPos).Config[a] != Gap))
5245  {
5246  TrackElementAt(1256, x).ConnLinkPos[y] = a;
5247  // note - this ensures that if the connecting element is a leading point
5248  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
5249  // (Points have the same link value for both [0] and [2])
5250  LinkFoundFlag = true;
5251  break; // stop after first find or will find later link for leading point
5252  }
5253  }
5254  if(!LinkFoundFlag)
5255  {
5256  if(FinalCall)
5257  {
5258  throw Exception("Error in final track linkage in LinkTrackNoMessages - invalid link");
5259  }
5260  Utilities->CallLogPop(1128);
5261  return(false);
5262  }
5263  }
5264  else // if(ConnectionFoundFlag)
5265  {
5266  if(FinalCall)
5267  {
5268  throw Exception("Error in final track linkage in LinkTrackNoMessages - connection not found");
5269  }
5270  Utilities->CallLogPop(1129);
5271  return(false);
5272  }
5273  }
5274  } // for(unsigned int x=0;x<TrackVector.size();x++)
5275 
5276  if(FinalCall)
5277  {
5279  }
5280 // final check
5281  bool ConnErrorFlag = false;
5282 
5283  for(unsigned int x = 0; x < TrackVector.size(); x++)
5284  {
5285  if((TrackElementAt(1257, x).Link[0] > 0) && (TrackElementAt(1258, x).Config[0] != End) && (TrackElementAt(1259, x).Conn[0] == -1))
5286  {
5287  ConnErrorFlag = true;
5288  }
5289  if((TrackElementAt(1260, x).Link[1] > 0) && (TrackElementAt(1261, x).Config[1] != End) && (TrackElementAt(1262, x).Conn[1] == -1))
5290  {
5291  ConnErrorFlag = true;
5292  }
5293  if((TrackElementAt(1263, x).Link[2] > 0) && (TrackElementAt(1264, x).Config[2] != End) && (TrackElementAt(1265, x).Conn[2] == -1))
5294  {
5295  ConnErrorFlag = true;
5296  }
5297  if((TrackElementAt(1266, x).Link[3] > 0) && (TrackElementAt(1267, x).Config[3] != End) && (TrackElementAt(1268, x).Conn[3] == -1))
5298  {
5299  ConnErrorFlag = true;
5300  }
5301  if(FinalCall) // StationStopLinks only set during FinalCall so only check at FinalCall
5302  {
5303  if(TrackElementAt(1269, x).ActiveTrackElementName == "")
5304  {
5305  if((TrackElementAt(1270, x).StationEntryStopLinkPos1 != -1) || (TrackElementAt(1271, x).StationEntryStopLinkPos2 != -1))
5306  {
5307  throw Exception("Error, StationEntryStopLinkPos not -1 for unnamed element at TrackVectorPosition = " + AnsiString(x));
5308  }
5309  }
5310  }
5311  }
5312  if(ConnErrorFlag)
5313  {
5314  if(FinalCall)
5315  {
5316  throw Exception("ConnError in LinkTrack - Final");
5317  }
5318  else
5319  {
5320  throw Exception("ConnError in LinkTrack - Precheck");
5321  }
5322  }
5323  bool CLkErrorFlag = false;
5324 
5325  for(unsigned int x = 0; x < TrackVector.size(); x++)
5326  {
5327  if((TrackElementAt(1272, x).Link[0] > 0) && (TrackElementAt(1273, x).Config[0] != End) && (TrackElementAt(1274, x).ConnLinkPos[0] == -1))
5328  {
5329  CLkErrorFlag = true;
5330  }
5331  if((TrackElementAt(1275, x).Link[1] > 0) && (TrackElementAt(1276, x).Config[1] != End) && (TrackElementAt(1277, x).ConnLinkPos[1] == -1))
5332  {
5333  CLkErrorFlag = true;
5334  }
5335  if((TrackElementAt(1278, x).Link[2] > 0) && (TrackElementAt(1279, x).Config[2] != End) && (TrackElementAt(1280, x).ConnLinkPos[2] == -1))
5336  {
5337  CLkErrorFlag = true;
5338  }
5339  if((TrackElementAt(1281, x).Link[3] > 0) && (TrackElementAt(1282, x).Config[3] != End) && (TrackElementAt(1283, x).ConnLinkPos[3] == -1))
5340  {
5341  CLkErrorFlag = true;
5342  }
5343  }
5344 
5345  if(CLkErrorFlag)
5346  {
5347  if(FinalCall)
5348  {
5349  throw Exception("CLkError in LinkTrack - Final");
5350  }
5351  else
5352  {
5353  throw Exception("CLkError in LinkTrack - Precheck");
5354  }
5355  }
5356 // set element lengths to min of 10m
5357  for(unsigned int x = 0; x < TrackVector.size(); x++)
5358  {
5359  if(TrackElementAt(1284, x).TrackType == Erase)
5360  {
5361  continue; // skip blank elements
5362  }
5363  if((TrackElementAt(1285, x).Length01 < 10) && (TrackElementAt(1436, x).Length23 != -1))
5364  {
5365  TrackElementAt(1286, x).Length01 = 10;
5366  }
5367  if((TrackElementAt(1287, x).Length23 < 10) && (TrackElementAt(1288, x).Length23 != -1))
5368  {
5369  TrackElementAt(1289, x).Length23 = 10;
5370  }
5371  }
5372 
5373  if(FinalCall) // ONLY at FinalCall, no point calling twice
5374  {
5375  CalcHLocMinEtc(7);
5376  }
5377  Utilities->CallLogPop(1130);
5378  return(true);
5379 }
5380 
5381 // ---------------------------------------------------------------------------
5382 
5383 bool TTrack::IsTrackLinked(int Caller) // not used any more
5384 {
5385  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsTrackLinked");
5386  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
5387  {
5388  if(TrackElementAt(1290, x).TrackType == Erase)
5389  {
5390  Utilities->CallLogPop(498);
5391  return(false);
5392  }
5393 // check foot linkages
5394  if(TrackElementAt(1291, x).TrackType == FootCrossing)
5395  {
5396  if(!CheckFootCrossingLinks(2, TrackElementAt(1292, x)))
5397  {
5398  Utilities->CallLogPop(499);
5399  return(false);
5400  }
5401  }
5402  for(unsigned int y = 0; y < 4; y++) // check all links for each element
5403  {
5404  if(TrackElementAt(1293, x).Link[y] <= 0)
5405  {
5406  continue; // no link
5407  }
5408  if(TrackElementAt(1294, x).Config[y] == End)
5409  {
5410  continue; // buffer or continuation
5411  }
5412  if(TrackElementAt(1295, x).Config[y] == Gap)
5413  {
5414  continue; // gaps set later from GapMap
5415 
5416  }
5417  // get required H & V for track element joining link 'y'
5418  int NewHLoc = TrackElementAt(1296, x).HLoc + LinkHVArray[TrackElementAt(1297, x).Link[y]][0];
5419  int NewVLoc = TrackElementAt(1298, x).VLoc + LinkHVArray[TrackElementAt(1299, x).Link[y]][1];
5420  // find track element if present
5421  bool ConnectionFoundFlag = false;
5422  int VecPos = GetVectorPositionFromTrackMap(15, NewHLoc, NewVLoc, ConnectionFoundFlag);
5423  if(ConnectionFoundFlag)
5424  {
5425  TrackElementAt(1300, x).Conn[y] = VecPos;
5426  // find connecting link in the newly found track element if there is one & make buffer check
5427  bool LinkFoundFlag = false;
5428  if(((TrackElementAt(1301, x).TrackType == Points) || (TrackElementAt(1302, x).TrackType == SignalPost) || (TrackElementAt(1303, x).TrackType == Crossover)) &&
5429  (TrackElementAt(1304, VecPos).TrackType == Buffers))
5430  {
5431  Utilities->CallLogPop(500);
5432  return(false);
5433  }
5434  else if((TrackElementAt(1305, x).TrackType == SignalPost) && (TrackElementAt(1306, VecPos).TrackType == SignalPost) &&
5435  (TrackElementAt(1307, x).SpeedTag == TrackElementAt(1308, VecPos).SpeedTag))
5436  {
5437  Utilities->CallLogPop(501);
5438  return(false);
5439  }
5440  else if((TrackElementAt(1309, x).TrackType == SignalPost) && (TrackElementAt(1310, VecPos).TrackType == Continuation))
5441  {
5442  Utilities->CallLogPop(502);
5443  return(false);
5444  }
5445  else
5446  {
5447  for(unsigned int a = 0; a < 4; a++)
5448  {
5449  if((TrackElementAt(1311, VecPos).Link[a] == (10 - TrackElementAt(1312, x).Link[y])) && (TrackElementAt(1313, VecPos).Config[a] != End) &&
5450  (TrackElementAt(1314, VecPos).Config[a] != Gap))
5451  {
5452  TrackElementAt(1315, x).ConnLinkPos[y] = a;
5453  // note - this ensures that if the connecting element is a leading point
5454  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
5455  // (Points have the same link value for both [0] and [2])
5456  LinkFoundFlag = true;
5457  break; // stop after first find or will find later link for leading point
5458  }
5459  }
5460  }
5461  if(!LinkFoundFlag)
5462  {
5463  Utilities->CallLogPop(503);
5464  return(false);
5465  }
5466  }
5467  else // if(ConnectionFoundFlag)
5468  {
5469  Utilities->CallLogPop(504);
5470  return(false);
5471  }
5472  }
5473  } // for(unsigned int x=0;x<TrackVector.size();x++)
5474 
5475 // final check
5476  bool ConnErrorFlag = false;
5477 
5478  for(unsigned int x = 0; x < TrackVector.size(); x++)
5479  {
5480  if((TrackElementAt(1316, x).Link[0] > 0) && (TrackElementAt(1317, x).Config[0] != End) && (TrackElementAt(1318, x).Conn[0] == -1))
5481  {
5482  ConnErrorFlag = true;
5483  }
5484  if((TrackElementAt(1319, x).Link[1] > 0) && (TrackElementAt(1320, x).Config[1] != End) && (TrackElementAt(1321, x).Conn[1] == -1))
5485  {
5486  ConnErrorFlag = true;
5487  }
5488  if((TrackElementAt(1322, x).Link[2] > 0) && (TrackElementAt(1333, x).Config[2] != End) && (TrackElementAt(1334, x).Conn[2] == -1))
5489  {
5490  ConnErrorFlag = true;
5491  }
5492  if((TrackElementAt(1335, x).Link[3] > 0) && (TrackElementAt(1336, x).Config[3] != End) && (TrackElementAt(1337, x).Conn[3] == -1))
5493  {
5494  ConnErrorFlag = true;
5495  }
5496  }
5497  if(ConnErrorFlag)
5498  {
5499  Utilities->CallLogPop(505);
5500  return(false);
5501  }
5502  bool CLkErrorFlag = false;
5503 
5504  for(unsigned int x = 0; x < TrackVector.size(); x++)
5505  {
5506  if((TrackElementAt(1338, x).Link[0] > 0) && (TrackElementAt(1339, x).Config[0] != End) && (TrackElementAt(1340, x).ConnLinkPos[0] == -1))
5507  {
5508  CLkErrorFlag = true;
5509  }
5510  if((TrackElementAt(1341, x).Link[1] > 0) && (TrackElementAt(1342, x).Config[1] != End) && (TrackElementAt(1343, x).ConnLinkPos[1] == -1))
5511  {
5512  CLkErrorFlag = true;
5513  }
5514  if((TrackElementAt(1344, x).Link[2] > 0) && (TrackElementAt(1345, x).Config[2] != End) && (TrackElementAt(1346, x).ConnLinkPos[2] == -1))
5515  {
5516  CLkErrorFlag = true;
5517  }
5518  if((TrackElementAt(1347, x).Link[3] > 0) && (TrackElementAt(1394, x).Config[3] != End) && (TrackElementAt(1348, x).ConnLinkPos[3] == -1))
5519  {
5520  CLkErrorFlag = true;
5521  }
5522  }
5523 
5524  if(CLkErrorFlag)
5525  {
5526  Utilities->CallLogPop(506);
5527  return(false);
5528  }
5529  Utilities->CallLogPop(507);
5530  return(true);
5531 }
5532 
5533 // ---------------------------------------------------------------------------
5534 
5536 {
5537  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetGapsFromGapMap");
5538  int Position1, Position2;
5539  TTrackElement TrackElement1, TrackElement2;
5540  TGapMapIterator GapMapPtr;
5541 
5542  if(!GapMap.empty())
5543  {
5544  for(GapMapPtr = GapMap.begin(); GapMapPtr != GapMap.end(); GapMapPtr++)
5545  {
5546  int HLoc1 = GapMapPtr->first.first;
5547  int VLoc1 = GapMapPtr->first.second;
5548  int HLoc2 = GapMapPtr->second.first;
5549  int VLoc2 = GapMapPtr->second.second;
5550  if(!FindNonPlatformMatch(12, HLoc1, VLoc1, Position1, TrackElement1))
5551  {
5552  throw Exception("Failed to find H & V for gap1, GapMap in error");
5553  }
5554  if(!FindNonPlatformMatch(13, HLoc2, VLoc2, Position2, TrackElement2))
5555  {
5556  throw Exception("Failed to find H & V for gap2, GapMap in error");
5557  }
5558  if(TrackElementAt(9, Position1).TrackType != GapJump)
5559  {
5560  throw Exception("Element at Pos1 not a gap, GapMap in error");
5561  }
5562  if(TrackElementAt(10, Position2).TrackType != GapJump)
5563  {
5564  throw Exception("Element at Pos2 not a gap, GapMap in error");
5565  }
5566  TrackElementAt(11, Position1).Conn[0] = Position2;
5567  TrackElementAt(12, Position1).ConnLinkPos[0] = 0;
5568  TrackElementAt(13, Position2).Conn[0] = Position1;
5569  TrackElementAt(14, Position2).ConnLinkPos[0] = 0;
5570  }
5571  }
5572  Utilities->CallLogPop(510);
5573  return(true);
5574 }
5575 
5576 // ---------------------------------------------------------------------------
5577 
5578 void TTrack::TrackPush(int Caller, TTrackElement TrackElement)
5579 {
5580 // TIMPair MapEntry;
5581  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackPush," + AnsiString(TrackElement.HLoc) + "," +
5582  AnsiString(TrackElement.VLoc) + "," + AnsiString(TrackElement.SpeedTag));
5583  THVPair TrackMapKeyPair, InactiveTrackMapKeyPair;
5584  TTrackMapEntry TrackMapEntry, InactiveTrackMapEntry;
5585  TLocationNameMultiMapEntry LocationNameEntry;
5586 
5587  LocationNameEntry.first = TrackElement.LocationName;
5588  if((TrackElement.TrackType == Platform) || (TrackElement.TrackType == Concourse) || (TrackElement.TrackType == Parapet) ||
5589  (TrackElement.TrackType == NamedNonStationLocation) || (TrackElement.TrackType == LevelCrossing))
5590  {
5591 // check whether a similar element already at this position and if so ignore it (had error where allowed multiple NonStationNamedLocs)
5592 // could arise when loading old railways with multiple NonStationNamedLocs
5593  bool FoundFlag = false;
5594  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(20, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5595  if(FoundFlag)
5596  {
5597  if((InactiveTrackElementAt(97, IMPair.first).SpeedTag == TrackElement.SpeedTag) || (InactiveTrackElementAt(98,
5598  IMPair.second).SpeedTag == TrackElement.SpeedTag))
5599  {
5600  Utilities->CallLogPop(1813);
5601  return;
5602  }
5603  }
5604  InactiveTrackVector.push_back(TrackElement); // no erase elements involved in InactiveTrackVector
5605  InactiveTrackMapKeyPair.first = TrackElement.HLoc;
5606  InactiveTrackMapKeyPair.second = TrackElement.VLoc;
5607  InactiveTrackMapEntry.first = InactiveTrackMapKeyPair;
5608  InactiveTrackMapEntry.second = InactiveTrackVector.size() - 1;
5609  InactiveTrack2MultiMap.insert(InactiveTrackMapEntry);
5610  if(TrackElement.FixedNamedLocationElement)
5611  {
5612  LocationNameEntry.second = InactiveTrackVector.size() - 1; // add to LocationNameMultiMap
5613  LocationNameMultiMap.insert(LocationNameEntry);
5614  }
5615  if(TrackElement.HLoc < HLocMin)
5616  {
5617  HLocMin = TrackElement.HLoc;
5618  }
5619  if(TrackElement.HLoc > HLocMax)
5620  {
5621  HLocMax = TrackElement.HLoc;
5622  }
5623  if(TrackElement.VLoc < VLocMin)
5624  {
5625  VLocMin = TrackElement.VLoc;
5626  }
5627  if(TrackElement.VLoc > VLocMax)
5628  {
5629  VLocMax = TrackElement.VLoc;
5630  }
5631  }
5632  else
5633  {
5634 // check whether a similar element already at this position and if so ignore it (had error where allowed multiple NonStationNamedLocs)
5635 // shouldn't arise but leave in as a safeguard
5636  bool FoundFlag = false;
5637  int VecPos = GetVectorPositionFromTrackMap(44, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5638  if(FoundFlag)
5639  {
5640  if(TrackElementAt(816, VecPos).SpeedTag == TrackElement.SpeedTag)
5641  {
5642  Utilities->CallLogPop(1814);
5643  return;
5644  }
5645  }
5646  TrackVector.push_back(TrackElement); // add erase elements to vector to keep linkages correct (now dispensed with)
5647  if(TrackElement.TrackType != Erase) // don't add erase elements to TrackMap (dispensed with these but keep code)
5648  {
5649  TrackMapKeyPair.first = TrackElement.HLoc;
5650  TrackMapKeyPair.second = TrackElement.VLoc;
5651  TrackMapEntry.first = TrackMapKeyPair;
5652  TrackMapEntry.second = TrackVector.size() - 1;
5653  TrackMap.insert(TrackMapEntry);
5654  if(TrackElement.FixedNamedLocationElement)
5655  {
5656  LocationNameEntry.second = -(int)(TrackVector.size()); // add to LocationNameMultiMap TrackVector.size = Required value + 1, so ...second = -1-Requ'd value
5657  LocationNameMultiMap.insert(LocationNameEntry);
5658  }
5659  if(TrackElement.HLoc < HLocMin)
5660  {
5661  HLocMin = TrackElement.HLoc; // exclude erase elements as HLoc & VLoc set to -2000000000
5662  }
5663  if(TrackElement.HLoc > HLocMax)
5664  {
5665  HLocMax = TrackElement.HLoc;
5666  }
5667  if(TrackElement.VLoc < VLocMin)
5668  {
5669  VLocMin = TrackElement.VLoc;
5670  }
5671  if(TrackElement.VLoc > VLocMax)
5672  {
5673  VLocMax = TrackElement.VLoc;
5674  }
5675  }
5676  }
5677 // CheckMapAndTrack(6);//test drop these to speed up, still checked outside this function
5678 // CheckMapAndInactiveTrack(6);//test
5679 
5680 // CheckLocationNameMultiMap(14);//test Can't test here as when loading the ActiveTrackElementName elements will be out of step
5681 // with the Platforms until layout fully loaded
5682  Utilities->CallLogPop(511);
5683 }
5684 
5685 // ---------------------------------------------------------------------------
5686 
5687 int TTrack::GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
5688 {
5689  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionFromTrackMap," + AnsiString(HLoc) + "," +
5690  AnsiString(VLoc));
5691  THVPair TrackMapKeyPair;
5692 
5693  FoundFlag = false;
5694  TTrackMapIterator TrackMapPtr;
5695 
5696  TrackMapKeyPair.first = HLoc;
5697  TrackMapKeyPair.second = VLoc;
5698  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5699  if(TrackMapPtr == TrackMap.end())
5700  {
5701  Utilities->CallLogPop(512);
5702  return(-1); // nothing found
5703  }
5704  else
5705  {
5706  FoundFlag = true;
5707  Utilities->CallLogPop(513);
5708  return(TrackMapPtr->second);
5709  }
5710 }
5711 
5712 // ---------------------------------------------------------------------------
5713 
5714 TTrackElement &TTrack::GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
5715 {
5716  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackElementFromTrackMap," + AnsiString(HLoc) + "," +
5717  AnsiString(VLoc));
5718  THVPair TrackMapKeyPair;
5719  TTrackMapIterator TrackMapPtr;
5720 
5721  TrackMapKeyPair.first = HLoc;
5722  TrackMapKeyPair.second = VLoc;
5723  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5724  if(TrackMapPtr == TrackMap.end())
5725  {
5726  AnsiString Message = "Element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc);
5727  throw Exception(Message);
5728  }
5729  else
5730  {
5731  Utilities->CallLogPop(1943);
5732  return(TrackElementAt(871, TrackMapPtr->second));
5733  }
5734 }
5735 
5736 // ---------------------------------------------------------------------------
5737 
5738 TTrackElement &TTrack::GetTrackElementFromAnyTrackMap(int Caller, int HLoc, int VLoc, TTrackMap &Map, TTrackVector &Vector) //new at v2.9.0 for clipboard pref dirs
5739 { //modded at v2.9.2 to make Map & Vector references
5740  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackElementFromAnyTrackMap," + AnsiString(HLoc) + "," +
5741  AnsiString(VLoc));
5742  THVPair MapKeyPair;
5743  TTrackMapIterator MapPtr;
5744 
5745  MapKeyPair.first = HLoc;
5746  MapKeyPair.second = VLoc;
5747  MapPtr = Map.find(MapKeyPair);
5748  if(MapPtr == Map.end())
5749  {
5750  AnsiString Message = "Element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc) + " in GetTrackElementFromAnyTrackMap";
5751  throw Exception(Message);
5752  }
5753  else
5754  {
5755  Utilities->CallLogPop(2280);
5756  return(Vector.at(MapPtr->second));
5757  }
5758 }
5759 
5760 // ---------------------------------------------------------------------------
5761 
5763 {
5764  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetInactiveTrackElementFromTrackMap," + AnsiString(HLoc) + "," +
5765  AnsiString(VLoc));
5766  THVPair InactiveTrackMapKeyPair;
5767  TInactiveTrack2MultiMapIterator InactiveTrackMapPtr;
5768 
5769  InactiveTrackMapKeyPair.first = HLoc;
5770  InactiveTrackMapKeyPair.second = VLoc;
5771  InactiveTrackMapPtr = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // not interested in platforms so only need to find one
5772  if(InactiveTrackMapPtr == InactiveTrack2MultiMap.end())
5773  {
5774  AnsiString Message = "Inactive element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc);
5775  throw Exception(Message);
5776  }
5777  else
5778  {
5779  Utilities->CallLogPop(1949);
5780  return(InactiveTrackElementAt(34, InactiveTrackMapPtr->second));
5781  }
5782 }
5783 
5784 // ---------------------------------------------------------------------------
5785 
5786 bool TTrack::TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
5787 {
5788  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackElementPresentAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
5789  bool Present = true;
5790  THVPair TrackMapKeyPair;
5791  TTrackMapIterator TrackMapPtr;
5792 
5793  TrackMapKeyPair.first = HLoc;
5794  TrackMapKeyPair.second = VLoc;
5795  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5796  if(TrackMapPtr == TrackMap.end())
5797  {
5798  Present = false;
5799  }
5800  Utilities->CallLogPop(2057);
5801  return(Present);
5802 }
5803 
5804 // ---------------------------------------------------------------------------
5805 
5806 bool TTrack::InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
5807 {
5808  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveTrackElementPresentAtHV," + AnsiString(HLoc) + "," +
5809  AnsiString(VLoc));
5810  bool Present = true;
5811  THVPair InactiveTrackMapKeyPair;
5812  TInactiveTrack2MultiMapIterator InactiveTrackMapPtr;
5813 
5814  InactiveTrackMapKeyPair.first = HLoc;
5815  InactiveTrackMapKeyPair.second = VLoc;
5816  InactiveTrackMapPtr = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // not interested in platforms so only need to find one
5817  if(InactiveTrackMapPtr == InactiveTrack2MultiMap.end())
5818  {
5819  Present = false;
5820  }
5821  Utilities->CallLogPop(2058);
5822  return(Present);
5823 }
5824 
5825 // ---------------------------------------------------------------------------
5826 
5827 TTrack::TIMPair TTrack::GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
5828 // max number of elements is 2, for platforms
5829 // note that both elements of RetPair may be the same, if only one present in map
5830 {
5831  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionsFromInactiveTrackMap," + AnsiString(HLoc) + "," +
5832  AnsiString(VLoc));
5833  THVPair InactiveTrackMapKeyPair;
5834  TIMPair RetPair;
5835  TInactiveTrackRange InactiveTrackRange;
5836 
5837  FoundFlag = false;
5838  InactiveTrackMapKeyPair.first = HLoc;
5839  InactiveTrackMapKeyPair.second = VLoc;
5840  if(InactiveTrack2MultiMap.empty())
5841  {
5842  RetPair.first = 0;
5843  RetPair.second = 0;
5844  Utilities->CallLogPop(1815);
5845  return(RetPair); // map empty
5846  }
5847  InactiveTrackRange = InactiveTrack2MultiMap.equal_range(InactiveTrackMapKeyPair);
5848  if(InactiveTrackRange.first == InactiveTrackRange.second)
5849  {
5850  RetPair.first = 0;
5851  RetPair.second = 0;
5852  Utilities->CallLogPop(514);
5853  return(RetPair); // nothing found
5854  }
5855  else
5856  {
5857  RetPair.first = InactiveTrackRange.first->second;
5858  RetPair.second = (--InactiveTrackRange.second)->second;
5859  FoundFlag = true;
5860  Utilities->CallLogPop(515);
5861  return(RetPair);
5862  }
5863 }
5864 
5865 // ---------------------------------------------------------------------------
5866 
5867 bool TTrack::MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition)
5868 {
5869 // only change where have adjacent points with their diverging links connected - not appropriate for non-straight points
5870  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MatchingPoint," + AnsiString(TrackVectorPosition) + "," +
5871  AnsiString(DivergingPosition));
5872  TTrackElement T1 = TrackElementAt(15, TrackVectorPosition);
5873  TTrackElement T2 = TrackElementAt(16, DivergingPosition);
5874  int SpeedTag1 = T1.SpeedTag;
5875  int SpeedTag2 = T2.SpeedTag;
5876 
5877  if(T1.Attribute != T2.Attribute)
5878  {
5879  Utilities->CallLogPop(516);
5880  return(false);
5881  }
5882  if(((SpeedTag1 == 7) && (SpeedTag2 == 10)) || // straight track hor, diverging track vert
5883  ((SpeedTag1 == 10) && (SpeedTag2 == 7)) || ((SpeedTag1 == 8) && (SpeedTag2 == 9)) || ((SpeedTag1 == 9) && (SpeedTag2 == 8)) ||
5884  ((SpeedTag1 == 11) && (SpeedTag2 == 14)) || // straight track vert, diverging track hor
5885  ((SpeedTag1 == 14) && (SpeedTag2 == 11)) || ((SpeedTag1 == 12) && (SpeedTag2 == 13)) || ((SpeedTag1 == 13) && (SpeedTag2 == 12)) ||
5886  ((SpeedTag1 == 28) && (SpeedTag2 == 31)) || // straight track hor, diverging track 45 deg
5887  ((SpeedTag1 == 31) && (SpeedTag2 == 28)) || ((SpeedTag1 == 29) && (SpeedTag2 == 30)) || ((SpeedTag1 == 30) && (SpeedTag2 == 29)) ||
5888  ((SpeedTag1 == 32) && (SpeedTag2 == 35)) || // straight track vert, diverging track 45 deg
5889  ((SpeedTag1 == 35) && (SpeedTag2 == 32)) || ((SpeedTag1 == 33) && (SpeedTag2 == 34)) || ((SpeedTag1 == 34) && (SpeedTag2 == 33)) ||
5890  ((SpeedTag1 == 36) && (SpeedTag2 == 39)) || // straight track 45 deg, diverging track vert
5891  ((SpeedTag1 == 39) && (SpeedTag2 == 36)) || ((SpeedTag1 == 37) && (SpeedTag2 == 38)) || ((SpeedTag1 == 38) && (SpeedTag2 == 37)) ||
5892  ((SpeedTag1 == 40) && (SpeedTag2 == 43)) || // straight track 45 deg, diverging track hor
5893  ((SpeedTag1 == 43) && (SpeedTag2 == 40)) || ((SpeedTag1 == 41) && (SpeedTag2 == 42)) || ((SpeedTag1 == 42) && (SpeedTag2 == 41)))
5894  {
5895  Utilities->CallLogPop(517);
5896  return(true);
5897  }
5898  else
5899  {
5900  Utilities->CallLogPop(518);
5901  return(false);
5902  }
5903 }
5904 
5905 // ---------------------------------------------------------------------------
5906 
5907 /*
5908  bool TMapComp::operator() (const THVPair& lower, const THVPair& higher) const///HLoc VLoc
5909  {
5910  if(lower.second < higher.second) return true;
5911  else if(lower.second > higher.second) return false;
5912  else if(lower.second == higher.second)
5913  {
5914  if(lower.first < higher.first) return true;
5915  }
5916  return false;
5917  }
5918 */
5919 // ---------------------------------------------------------------------------
5920 
5921 void TTrack::PlotGap(int Caller, TTrackElement TrackElement, TDisplay *Disp)
5922 // no need to check corresponding gap, if that not set correctly it will be picked up in GapsUnset()
5923 {
5924  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotGap," + TrackElement.LogTrack(1));
5925  if(TrackElement.TrackType != GapJump)
5926  {
5927  throw Exception("Error, Wrong track type in PlotGap");
5928  }
5929  if((TrackElement.SpeedTag == 88) && (TrackElement.Conn[0] > -1))
5930  {
5931  Disp->PlotOutput(39, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl88set);
5932  }
5933  else if((TrackElement.SpeedTag == 88) && (TrackElement.Conn[0] == -1))
5934  {
5935  Disp->PlotOutput(40, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl88unset);
5936  }
5937  if((TrackElement.SpeedTag == 89) && (TrackElement.Conn[0] > -1))
5938  {
5939  Disp->PlotOutput(41, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl89set);
5940  }
5941  else if((TrackElement.SpeedTag == 89) && (TrackElement.Conn[0] == -1))
5942  {
5943  Disp->PlotOutput(42, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl89unset);
5944  }
5945  if((TrackElement.SpeedTag == 90) && (TrackElement.Conn[0] > -1))
5946  {
5947  Disp->PlotOutput(43, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl90set);
5948  }
5949  else if((TrackElement.SpeedTag == 90) && (TrackElement.Conn[0] == -1))
5950  {
5951  Disp->PlotOutput(44, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl90unset);
5952  }
5953  if((TrackElement.SpeedTag == 91) && (TrackElement.Conn[0] > -1))
5954  {
5955  Disp->PlotOutput(45, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl91set);
5956  }
5957  else if((TrackElement.SpeedTag == 91) && (TrackElement.Conn[0] == -1))
5958  {
5959  Disp->PlotOutput(46, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl91unset);
5960  }
5961  if((TrackElement.SpeedTag == 92) && (TrackElement.Conn[0] > -1))
5962  {
5963  Disp->PlotOutput(47, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl92set);
5964  }
5965  else if((TrackElement.SpeedTag == 92) && (TrackElement.Conn[0] == -1))
5966  {
5967  Disp->PlotOutput(48, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl92unset);
5968  }
5969  if((TrackElement.SpeedTag == 93) && (TrackElement.Conn[0] > -1))
5970  {
5971  Disp->PlotOutput(49, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm93set);
5972  }
5973  else if((TrackElement.SpeedTag == 93) && (TrackElement.Conn[0] == -1))
5974  {
5975  Disp->PlotOutput(50, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm93unset);
5976  }
5977  if((TrackElement.SpeedTag == 94) && (TrackElement.Conn[0] > -1))
5978  {
5979  Disp->PlotOutput(51, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm94set);
5980  }
5981  else if((TrackElement.SpeedTag == 94) && (TrackElement.Conn[0] == -1))
5982  {
5983  Disp->PlotOutput(52, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm94unset);
5984  }
5985  if((TrackElement.SpeedTag == 95) && (TrackElement.Conn[0] > -1))
5986  {
5987  Disp->PlotOutput(53, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl95set);
5988  }
5989  else if((TrackElement.SpeedTag == 95) && (TrackElement.Conn[0] == -1))
5990  {
5991  Disp->PlotOutput(54, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl95unset);
5992  }
5993  Utilities->CallLogPop(1101);
5994 }
5995 
5996 // ---------------------------------------------------------------------------
5997 
5998 void TTrack::PlotContinuation(int Caller, TTrackElement TrackElement, TDisplay *Disp) //added for multiplayer to add overlays where coupled
5999 {
6000  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotContinuation," + TrackElement.LogTrack(1));
6001  TrackElement.PlotVariableTrackElement(7, Disp);
6002  if(!MultiplayerOverlayMap.empty()) //if it is empty then no overlays needed [map of key = THVPair, value = graphic pointer]
6003  {
6004  THVPair PosPair;
6005  PosPair.first = TrackElement.HLoc;
6006  PosPair.second = TrackElement.VLoc;
6007  TMultiplayerOverlayMap::iterator MOMIt = MultiplayerOverlayMap.find(PosPair);
6008  if(MOMIt != MultiplayerOverlayMap.end()) //if it is then no overlay is needed
6009  {
6010  Disp->PlotOutput(283, TrackElement.HLoc * 16, TrackElement.VLoc * 16, MOMIt->second);
6011  }
6012  }
6013  Utilities->CallLogPop(2403);
6014 }
6015 
6016 // ---------------------------------------------------------------------------
6017 
6018 void TTrack::PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
6019 {
6020  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPoints," + TrackElement.LogTrack(2));
6021  if(TrackElement.TrackType != Points)
6022  {
6023  throw Exception("Error, Wrong track type in PlotPoints");
6024  }
6025  Disp->PlotPointBlank(0, TrackElement.HLoc, TrackElement.VLoc); // to get rid of earlier fillet
6026  TrackElement.PlotVariableTrackElement(4, Disp);
6027  if(BothFillets)
6028  {
6029  if(TrackElement.SpeedTag < 28)
6030  {
6031  Disp->PlotOutput(55, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][0]);
6032  Disp->PlotOutput(73, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][1]);
6033  }
6034  else if(TrackElement.SpeedTag < 132)
6035  {
6036  Disp->PlotOutput(56, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][0]);
6037  Disp->PlotOutput(74, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][1]);
6038  }
6039  else
6040  {
6041  Disp->PlotOutput(70, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][0]);
6042  Disp->PlotOutput(71, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][1]);
6043  }
6044  }
6045  else
6046  {
6047  if(TrackElement.SpeedTag < 28)
6048  {
6049  Disp->PlotOutput(75, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6050  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]);
6051  }
6052  else if(TrackElement.SpeedTag < 132)
6053  {
6054  Disp->PlotOutput(76, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6055  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]);
6056  }
6057  else
6058  {
6059  Disp->PlotOutput(72, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6060  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]);
6061  }
6062  }
6063 // replot platform if required
6064  TIMPair IMPair;
6065  bool FoundFlag;
6066 
6067  IMPair = GetVectorPositionsFromInactiveTrackMap(15, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
6068  if(FoundFlag)
6069  {
6070  // only one platform possible at points so only need to plot IMPair.first
6071  TTrackElement PlatElement = InactiveTrackElementAt(89, IMPair.first);
6072  PlatElement.PlotVariableTrackElement(5, Disp); // to plot as striped or non-striped depending on whether named or not
6073  }
6074  Utilities->CallLogPop(519);
6075 }
6076 
6077 // ---------------------------------------------------------------------------
6078 
6079 void TTrack::PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
6080 {
6081 // Can't use TrackElement.PlotVariableTrackElement() here as graphic changes depending on signal colour
6082  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSignal," + TrackElement.LogTrack(3));
6083  if(TrackElement.TrackType != SignalPost)
6084  {
6085  throw Exception("Error, Wrong track type in PlotSignal");
6086  }
6087  for(int x = 0; x < 40; x++)
6088  {
6089  if((SigTable[x].SpeedTag == TrackElement.SpeedTag) && (SigTable[x].Attribute == TrackElement.Attribute))
6090  {
6091  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
6092  Disp->PlotSignalBlank(0, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
6093 // in case existing signal is a double yellow
6094  // plot platforms if present
6095 // Graphics::TBitmap* SignalPlatformGraphic;
6096 // if(PlatformOnSignalSide(0, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, SignalPlatformGraphic))
6097 // Above dropped at v2.3.0. Now plot either or both platforms if present regardless of which side they are on. The platforms will
6098 // be consistent with the signal graphic as can't enter an inappropriate platform. The new right hand signal option caused platforms
6099 // to not be plotted with the above function.
6100  PlotSignalPlatforms(0, TrackElement.HLoc, TrackElement.VLoc, Disp); // if no platforms nothing is plotted
6101  // now plot signal (double yellow overwrites most of signal platform if present)
6102  // additions at version 0.6 for other aspects & ground sigs
6103  if(TrackElement.SigAspect == TTrackElement::ThreeAspect)
6104  {
6105  Disp->PlotOutput(117, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableThreeAspect[x].SigPtr);
6106  }
6107  else if(TrackElement.SigAspect == TTrackElement::TwoAspect)
6108  {
6109  Disp->PlotOutput(118, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableTwoAspect[x].SigPtr);
6110  }
6111  else if(TrackElement.SigAspect == TTrackElement::GroundSignal)
6112  {
6113  Disp->PlotOutput(119, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableGroundSignal[x].SigPtr);
6114  }
6115  else // 4 aspect
6116  {
6117  Disp->PlotOutput(58, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTable[x].SigPtr);
6118  }
6119  if((TrackElement.CallingOnSet) && (TrackElement.SigAspect != TTrackElement::GroundSignal))
6120  // normal signal calling on, need to add extra graphic, basic red signal plotted above from SigTable
6121  {
6122  if(TrackElement.SpeedTag == 68)
6123  {
6124  Disp->PlotOutput(59, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm68CallingOn);
6125  }
6126  if(TrackElement.SpeedTag == 69)
6127  {
6128  Disp->PlotOutput(60, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm69CallingOn);
6129  }
6130  if(TrackElement.SpeedTag == 70)
6131  {
6132  Disp->PlotOutput(61, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm70CallingOn);
6133  }
6134  if(TrackElement.SpeedTag == 71)
6135  {
6136  Disp->PlotOutput(62, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm71CallingOn);
6137  }
6138  if(TrackElement.SpeedTag == 72)
6139  {
6140  Disp->PlotOutput(63, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm72CallingOn);
6141  }
6142  if(TrackElement.SpeedTag == 73)
6143  {
6144  Disp->PlotOutput(64, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm73CallingOn);
6145  }
6146  if(TrackElement.SpeedTag == 74)
6147  {
6148  Disp->PlotOutput(65, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm74CallingOn);
6149  }
6150  if(TrackElement.SpeedTag == 75)
6151  {
6152  Disp->PlotOutput(66, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm75CallingOn);
6153  }
6154  }
6155  else if((TrackElement.CallingOnSet) && (TrackElement.SigAspect == TTrackElement::GroundSignal))
6156  // ground signal calling on, need to use normal proceed aspect
6157  {
6158  for(int x = 0; x < 40; x++)
6159  {
6160  if((SigTableGroundSignal[x].SpeedTag == TrackElement.SpeedTag) && (SigTable[x].Attribute == 1)) // use attr 1 for proceed
6161  {
6162  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
6163  Disp->PlotSignalBlank(1, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
6164  // plot special signal platform if present
6165  Graphics::TBitmap* SignalPlatformGraphic;
6166  PlotSignalPlatforms(1, TrackElement.HLoc, TrackElement.VLoc, Disp);
6167  // now plot signal
6168  Disp->PlotOutput(123, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableGroundSignal[x].SigPtr);
6169  }
6170  }
6171  }
6172  break;
6173  }
6174  }
6175  Utilities->CallLogPop(520);
6176 }
6177 
6178 // ---------------------------------------------------------------------------
6179 
6180 void TTrack::PlotSignalPlatforms(int Caller, int HLoc, int VLoc, TDisplay *Disp)
6181 {
6182  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSignalPlatforms," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6183  bool FoundFlag;
6184  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(13, HLoc, VLoc, FoundFlag);
6185 
6186  if(!FoundFlag)
6187  {
6188  Utilities->CallLogPop(2112);
6189  return;
6190  }
6191  TTrackElement IAElement1 = InactiveTrackElementAt(124, IMPair.first);
6192  TTrackElement IAElement2 = InactiveTrackElementAt(125, IMPair.second);
6193 
6194  // don't want 'else if' for the below as may need to plot 2 platforms
6195  if((IAElement1.SpeedTag == 76) || (IAElement2.SpeedTag == 76)) // top plat
6196  {
6197  if(IAElement1.LocationName == "") // '2' will be same
6198  {
6199  Disp->PlotOutput(239, HLoc * 16, VLoc * 16, RailGraphics->gl76Striped);
6200  }
6201  else
6202  {
6203  Disp->PlotOutput(240, HLoc * 16, VLoc * 16, RailGraphics->gl76);
6204  }
6205  }
6206  if((IAElement1.SpeedTag == 77) || (IAElement2.SpeedTag == 77)) // bot plat
6207  {
6208  if(IAElement1.LocationName == "") // '2' will be same
6209  {
6210  Disp->PlotOutput(241, HLoc * 16, VLoc * 16, RailGraphics->bm77Striped);
6211  }
6212  else
6213  {
6214  Disp->PlotOutput(242, HLoc * 16, VLoc * 16, RailGraphics->bm77);
6215  }
6216  }
6217  if((IAElement1.SpeedTag == 78) || (IAElement2.SpeedTag == 78)) // lh plat
6218  {
6219  if(IAElement1.LocationName == "") // '2' will be same
6220  {
6221  Disp->PlotOutput(243, HLoc * 16, VLoc * 16, RailGraphics->bm78Striped);
6222  }
6223  else
6224  {
6225  Disp->PlotOutput(244, HLoc * 16, VLoc * 16, RailGraphics->bm78);
6226  }
6227  }
6228  if((IAElement1.SpeedTag == 79) || (IAElement2.SpeedTag == 79)) // rh plat
6229  {
6230  if(IAElement1.LocationName == "") // '2' will be same
6231  {
6232  Disp->PlotOutput(245, HLoc * 16, VLoc * 16, RailGraphics->gl79Striped);
6233  }
6234  else
6235  {
6236  Disp->PlotOutput(246, HLoc * 16, VLoc * 16, RailGraphics->gl79);
6237  }
6238  }
6239  Utilities->CallLogPop(2113);
6240 }
6241 
6242 // ---------------------------------------------------------------------------
6243 
6244 void TTrack::SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
6245 {
6246 // Set attrs to 0=closed to trains; 1=open to trains; 2 = changing = closed to trains
6247  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LowerLinkedLevelCrossingBarrierAttributes," + AnsiString(HLoc) + "," +
6248  AnsiString(VLoc));
6249 // find topmost LC, opening them all (to trains) in turn
6250  int UpStep = 0;
6251 
6252  while(IsLCAtHV(0, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6253  {
6254  SetLCAttributeAtHV(0, HLoc, (VLoc + UpStep), Attr);
6255  UpStep--;
6256  }
6257 // now find bottommost LC, opening them all (to trains) in turn
6258  int DownStep = 1;
6259 
6260  while(IsLCAtHV(1, HLoc, (VLoc + DownStep)))
6261  {
6262  SetLCAttributeAtHV(1, HLoc, (VLoc + DownStep), Attr);
6263  DownStep++;
6264  }
6265 // find leftmost LC, opening them all (to trains) in turn
6266  int LeftStep = 0;
6267 
6268  while(IsLCAtHV(2, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
6269  {
6270  SetLCAttributeAtHV(2, (HLoc + LeftStep), VLoc, Attr);
6271  LeftStep--;
6272  }
6273 // now find rightmost LC, opening them all (to trains) in turn
6274  int RightStep = 1;
6275 
6276  while(IsLCAtHV(3, (HLoc + RightStep), VLoc))
6277  {
6278  SetLCAttributeAtHV(3, (HLoc + RightStep), VLoc, Attr);
6279  RightStep++;
6280  }
6281  Utilities->CallLogPop(1915);
6282 }
6283 
6284 // ---------------------------------------------------------------------------
6285 
6286 void TTrack::SetLinkedManualLCs(int Caller, int HLoc, int VLoc) //sets TypeOfRoute to 2 for all linked LCs
6287 {
6288  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLinkedManualLCs," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6289 // work upwards setting all to manual
6290  int UpStep = -1;
6291 
6292  while(IsLCAtHV(51, HLoc, (VLoc + UpStep)))
6293  {
6294  SetBarriersDownLCToManual(0, HLoc, (VLoc + UpStep));
6295  UpStep--;
6296  }
6297 // work downwards setting all to manual
6298  int DownStep = 1;
6299 
6300  while(IsLCAtHV(52, HLoc, (VLoc + DownStep)))
6301  {
6302  SetBarriersDownLCToManual(1, HLoc, (VLoc + DownStep));
6303  DownStep++;
6304  }
6305 // work leftwards setting all to manual
6306  int LeftStep = -1;
6307 
6308  while(IsLCAtHV(53, (HLoc + LeftStep), VLoc))
6309  {
6310  SetBarriersDownLCToManual(2, (HLoc + LeftStep), VLoc);
6311  LeftStep--;
6312  }
6313 // work rightwards setting all to manual
6314  int RightStep = 1;
6315 
6316  while(IsLCAtHV(54, (HLoc + RightStep), VLoc))
6317  {
6318  SetBarriersDownLCToManual(3, (HLoc + RightStep), VLoc);
6319  RightStep++;
6320  }
6321  Utilities->CallLogPop(2242);
6322 }
6323 
6324 // ---------------------------------------------------------------------------
6325 
6326 void TTrack::SetBarriersDownLCToManual(int Caller, int HLoc, int VLoc)
6327 {
6328  // Set TypeOfRoute value to 2 to indicate barriers manually closed
6329  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetBarriersDownLCToManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6330  for(unsigned int x = 0; x < BarriersDownVector.size(); x++)
6331  {
6332  if((BarriersDownVector.at(x).HLoc == HLoc) && (BarriersDownVector.at(x).VLoc == VLoc))
6333  {
6334  BarriersDownVector.at(x).TypeOfRoute = 2;
6335  break;
6336  }
6337  }
6338  Utilities->CallLogPop(2243);
6339 }
6340 
6341 // ---------------------------------------------------------------------------
6342 
6343 bool TTrack::AnyLinkedBarrierDownVectorManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
6344 {
6345  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AnyLinkedBarrierDownVectorManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6346 // work upwards
6347  int UpStep = 0; //start with this location
6348 
6349  while(IsLCAtHV(55, HLoc, (VLoc + UpStep)))
6350  {
6351  if(IsBarrierDownVectorAtHVManual(0, HLoc, (VLoc + UpStep), BDVectorPos))
6352  {
6353  Utilities->CallLogPop(2244);
6354  return(true);
6355  }
6356  UpStep--;
6357  }
6358 // work downwards
6359  int DownStep = 1;
6360 
6361  while(IsLCAtHV(56, HLoc, (VLoc + DownStep)))
6362  {
6363  if(IsBarrierDownVectorAtHVManual(1, HLoc, (VLoc + DownStep), BDVectorPos))
6364  {
6365  Utilities->CallLogPop(2245);
6366  return(true);
6367  }
6368  DownStep++;
6369  }
6370 // work leftwards
6371  int LeftStep = -1;
6372 
6373  while(IsLCAtHV(57, (HLoc + LeftStep), VLoc))
6374  {
6375  if(IsBarrierDownVectorAtHVManual(2, (HLoc + LeftStep), VLoc, BDVectorPos))
6376  {
6377  Utilities->CallLogPop(2246);
6378  return(true);
6379  }
6380  LeftStep--;
6381  }
6382 // work rightwards
6383  int RightStep = 1;
6384 
6385  while(IsLCAtHV(58, (HLoc + RightStep), VLoc))
6386  {
6387  if(IsBarrierDownVectorAtHVManual(3, (HLoc + RightStep), VLoc, BDVectorPos))
6388  {
6389  Utilities->CallLogPop(2247);
6390  return(true);
6391  }
6392  RightStep++;
6393  }
6394  Utilities->CallLogPop(2248);
6395  return(false);
6396 }
6397 
6398 // ---------------------------------------------------------------------------
6399 
6400 bool TTrack::IsBarrierDownVectorAtHVManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
6401 {
6402  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierDownVectorAtHVManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6403  for(unsigned int x = 0; x < BarriersDownVector.size(); x++)
6404  {
6405  if((BarriersDownVector.at(x).HLoc == HLoc) && (BarriersDownVector.at(x).VLoc == VLoc) && (BarriersDownVector.at(x).TypeOfRoute == 2))
6406  {
6407  BDVectorPos = x;
6408  Utilities->CallLogPop(2249);
6409  return(true);
6410  }
6411  }
6412  BDVectorPos = -1;
6413  Utilities->CallLogPop(2250);
6414  return(false);
6415 }
6416 
6417 // ---------------------------------------------------------------------------
6418 
6419 void TTrack::PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp, bool Manual)
6420 // open to trains
6421 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6422 {
6423  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotLoweredLinkedLevelCrossingBarriers," + AnsiString(HLoc) + "," +
6424  AnsiString(VLoc));
6425  if(!IsLCAtHV(4, HLoc, VLoc))
6426  {
6427  throw Exception("Error, Wrong track type in PlotAndLowerLevelCrossingBarriers");
6428  }
6429  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
6430  {
6431  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotAndLowerLevelCrossingBarriers");
6432  }
6433 // check for adjacent LCs & if so open (to trains)
6434  if(BaseElementSpeedTag == 1) // hor track element
6435  {
6436  // find topmost LC, opening them all (to trains) in turn
6437  int UpStep = 0;
6438  while(IsLCAtHV(5, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6439  {
6440  UpStep--;
6441  }
6442  UpStep++;
6443  // now find bottommost LC, opening them all (to trains) in turn
6444  int DownStep = 1;
6445  while(IsLCAtHV(6, HLoc, (VLoc + DownStep)))
6446  {
6447  DownStep++;
6448  }
6449  DownStep--;
6450  // now plot graphics, UpStep is smallest & DownStep largest
6451  // RouteGraphic is the coloured track element, BaseGraphic is non-coloured
6452  // Only need to plot the coloured graphic for the HLoc & VLoc in the vector as that is the route that is causeing the LC to flash
6453  Graphics::TBitmap *RouteGraphic;
6454  Graphics::TBitmap *BaseGraphic = RailGraphics->gl1;
6455  if(TypeOfRoute == 1)
6456  {
6457  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[0];
6458  }
6459  else if(TypeOfRoute == 0)
6460  {
6461  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[0];
6462  }
6463  else //manual - no route
6464  {
6465  RouteGraphic = BaseGraphic;
6466  }
6467 // LinkSigRouteGraphicsPtr[0] hor } pref dir
6468 // LinkSigRouteGraphicsPtr[1] ver }
6469 // LinkNonSigRouteGraphicsPtr[0] hor } non pref dir
6470 // LinkNonSigRouteGraphicsPtr[1] ver }
6471 
6472  if(UpStep == DownStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6473  {
6474  Disp->PlotOutput(132, HLoc * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6475  Disp->PlotOutput(133, HLoc * 16, VLoc * 16, RouteGraphic);
6476  if(!Manual)
6477  {
6478  Disp->PlotOutput(134, HLoc * 16, VLoc * 16, RailGraphics->LCBothHor);
6479  }
6480  else
6481  {
6482  Disp->PlotOutput(247, HLoc * 16, VLoc * 16, RailGraphics->LCBothHorMan);
6483  }
6484  }
6485  else if((DownStep - UpStep) == 1) // double track, no need for any plain LC graphics
6486  {
6487  if(UpStep == 0)
6488  {
6489  Disp->PlotOutput(135, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6490  Disp->PlotOutput(136, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
6491  if(!Manual)
6492  {
6493  Disp->PlotOutput(137, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6494  }
6495  else
6496  {
6497  Disp->PlotOutput(248, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6498  }
6499  Disp->PlotOutput(138, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6500  Disp->PlotOutput(139, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6501  if(!Manual)
6502  {
6503  Disp->PlotOutput(140, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6504  }
6505  else
6506  {
6507  Disp->PlotOutput(249, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6508  }
6509  }
6510  else
6511  {
6512  Disp->PlotOutput(195, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6513  Disp->PlotOutput(196, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6514  if(!Manual)
6515  {
6516  Disp->PlotOutput(197, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6517  }
6518  else
6519  {
6520  Disp->PlotOutput(250, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6521  }
6522  Disp->PlotOutput(198, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6523  Disp->PlotOutput(199, HLoc * 16, (VLoc + DownStep) * 16, RouteGraphic);
6524  if(!Manual)
6525  {
6526  Disp->PlotOutput(200, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6527  }
6528  else
6529  {
6530  Disp->PlotOutput(251, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6531  }
6532  }
6533  }
6534  else // at least one plain graphic
6535  {
6536  if(UpStep == 0)
6537  {
6538  Disp->PlotOutput(141, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6539  Disp->PlotOutput(142, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
6540  if(!Manual)
6541  {
6542  Disp->PlotOutput(143, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6543  }
6544  else
6545  {
6546  Disp->PlotOutput(252, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6547  }
6548  Disp->PlotOutput(144, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6549  Disp->PlotOutput(145, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6550  if(!Manual)
6551  {
6552  Disp->PlotOutput(146, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6553  }
6554  else
6555  {
6556  Disp->PlotOutput(253, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6557  }
6558  }
6559  else if(DownStep == 0)
6560  {
6561  Disp->PlotOutput(201, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6562  Disp->PlotOutput(202, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6563  if(!Manual)
6564  {
6565  Disp->PlotOutput(203, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6566  }
6567  else
6568  {
6569  Disp->PlotOutput(254, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6570  }
6571  Disp->PlotOutput(204, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6572  Disp->PlotOutput(205, HLoc * 16, (VLoc + DownStep) * 16, RouteGraphic);
6573  if(!Manual)
6574  {
6575  Disp->PlotOutput(206, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6576  }
6577  else
6578  {
6579  Disp->PlotOutput(255, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6580  }
6581  }
6582  else
6583  {
6584  Disp->PlotOutput(207, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6585  Disp->PlotOutput(208, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6586  if(!Manual)
6587  {
6588  Disp->PlotOutput(209, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6589  }
6590  else
6591  {
6592  Disp->PlotOutput(256, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6593  }
6594  Disp->PlotOutput(210, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6595  Disp->PlotOutput(211, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6596  if(!Manual)
6597  {
6598  Disp->PlotOutput(212, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6599  }
6600  else
6601  {
6602  Disp->PlotOutput(257, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6603  }
6604  }
6605  for(int x = (UpStep + 1); x < DownStep; x++)
6606  {
6607  Disp->PlotOutput(147, HLoc * 16, (VLoc + x) * 16, RailGraphics->bmSolidBgnd);
6608  if(x == 0)
6609  {
6610  Disp->PlotOutput(148, HLoc * 16, (VLoc + x) * 16, RouteGraphic);
6611  }
6612  else
6613  {
6614  Disp->PlotOutput(213, HLoc * 16, (VLoc + x) * 16, BaseGraphic);
6615  }
6616  if(!Manual)
6617  {
6618  Disp->PlotOutput(149, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlain);
6619  }
6620  else
6621  {
6622  Disp->PlotOutput(258, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlainMan);
6623  }
6624  }
6625  }
6626  Disp->Update();
6627  Utilities->CallLogPop(1958);
6628  return;
6629  }
6630 
6631  else // ver track element
6632  {
6633  // find leftmost LC, opening them all (to trains) in turn
6634  int LStep = 0;
6635  while(IsLCAtHV(7, (HLoc + LStep), VLoc))
6636  {
6637  LStep--;
6638  }
6639  LStep++;
6640  // now find rightmost LC, opening them all (to trains) in turn
6641  int RStep = 1;
6642  while(IsLCAtHV(8, (HLoc + RStep), VLoc))
6643  {
6644  RStep++;
6645  }
6646  RStep--;
6647  // now plot graphics, LStep is smallest & RStep largest
6648  Graphics::TBitmap *RouteGraphic;
6649  Graphics::TBitmap *BaseGraphic = RailGraphics->gl2;
6650  if(TypeOfRoute == 1)
6651  {
6652  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[1];
6653  }
6654  else if(TypeOfRoute == 0)
6655  {
6656  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[1];
6657  }
6658  else //manual
6659  {
6660  RouteGraphic = BaseGraphic;
6661  }
6662 // LinkSigRouteGraphicsPtr[0] hor } pref dir
6663 // LinkSigRouteGraphicsPtr[1] ver }
6664 // LinkNonSigRouteGraphicsPtr[0] hor } non pref dir
6665 // LinkNonSigRouteGraphicsPtr[1] ver }
6666  if(LStep == RStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6667  {
6668  Disp->PlotOutput(150, HLoc * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6669  Disp->PlotOutput(151, HLoc * 16, VLoc * 16, RouteGraphic);
6670  if(!Manual)
6671  {
6672  Disp->PlotOutput(152, HLoc * 16, VLoc * 16, RailGraphics->LCBothVer);
6673  }
6674  else
6675  {
6676  Disp->PlotOutput(259, HLoc * 16, VLoc * 16, RailGraphics->LCBothVerMan);
6677  }
6678  }
6679  else if((RStep - LStep) == 1) // double track, no need for any plain LC graphics
6680  {
6681  if(LStep == 0)
6682  {
6683  Disp->PlotOutput(153, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6684  Disp->PlotOutput(154, (HLoc + LStep) * 16, VLoc * 16, RouteGraphic);
6685  if(!Manual)
6686  {
6687  Disp->PlotOutput(155, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6688  }
6689  else
6690  {
6691  Disp->PlotOutput(260, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6692  }
6693  Disp->PlotOutput(156, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6694  Disp->PlotOutput(157, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6695  if(!Manual)
6696  {
6697  Disp->PlotOutput(158, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6698  }
6699  else
6700  {
6701  Disp->PlotOutput(261, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6702  }
6703  }
6704  else
6705  {
6706  Disp->PlotOutput(214, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6707  Disp->PlotOutput(215, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6708  if(!Manual)
6709  {
6710  Disp->PlotOutput(216, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6711  }
6712  else
6713  {
6714  Disp->PlotOutput(262, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6715  }
6716  Disp->PlotOutput(217, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6717  Disp->PlotOutput(218, (HLoc + RStep) * 16, VLoc * 16, RouteGraphic);
6718  if(!Manual)
6719  {
6720  Disp->PlotOutput(219, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6721  }
6722  else
6723  {
6724  Disp->PlotOutput(263, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6725  }
6726  }
6727  }
6728  else // at least one plain graphic
6729  {
6730  if(LStep == 0)
6731  {
6732  Disp->PlotOutput(159, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6733  Disp->PlotOutput(160, (HLoc + LStep) * 16, VLoc * 16, RouteGraphic);
6734  if(!Manual)
6735  {
6736  Disp->PlotOutput(161, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6737  }
6738  else
6739  {
6740  Disp->PlotOutput(264, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6741  }
6742  Disp->PlotOutput(162, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6743  Disp->PlotOutput(163, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6744  if(!Manual)
6745  {
6746  Disp->PlotOutput(164, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6747  }
6748  else
6749  {
6750  Disp->PlotOutput(265, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6751  }
6752  }
6753  else if(RStep == 0)
6754  {
6755  Disp->PlotOutput(220, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6756  Disp->PlotOutput(221, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6757  if(!Manual)
6758  {
6759  Disp->PlotOutput(222, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6760  }
6761  else
6762  {
6763  Disp->PlotOutput(266, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6764  }
6765  Disp->PlotOutput(223, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6766  Disp->PlotOutput(224, (HLoc + RStep) * 16, VLoc * 16, RouteGraphic);
6767  if(!Manual)
6768  {
6769  Disp->PlotOutput(225, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6770  }
6771  else
6772  {
6773  Disp->PlotOutput(267, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6774  }
6775  }
6776  else
6777  {
6778  Disp->PlotOutput(226, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6779  Disp->PlotOutput(227, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6780  if(!Manual)
6781  {
6782  Disp->PlotOutput(228, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6783  }
6784  else
6785  {
6786  Disp->PlotOutput(268, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6787  }
6788  Disp->PlotOutput(229, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6789  Disp->PlotOutput(230, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6790  if(!Manual)
6791  {
6792  Disp->PlotOutput(231, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6793  }
6794  else
6795  {
6796  Disp->PlotOutput(269, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6797  }
6798  }
6799  for(int x = (LStep + 1); x < RStep; x++)
6800  {
6801  Disp->PlotOutput(165, (HLoc + x) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6802  if(x == 0)
6803  {
6804  Disp->PlotOutput(166, (HLoc + x) * 16, VLoc * 16, RouteGraphic);
6805  }
6806  else
6807  {
6808  Disp->PlotOutput(232, (HLoc + x) * 16, VLoc * 16, BaseGraphic);
6809  }
6810  if(!Manual)
6811  {
6812  Disp->PlotOutput(167, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlain);
6813  }
6814  else
6815  {
6816  Disp->PlotOutput(270, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlainMan);
6817  }
6818  }
6819  }
6820  Disp->Update();
6821  Utilities->CallLogPop(1896);
6822  return;
6823  }
6824 }
6825 
6826 // ---------------------------------------------------------------------------
6827 
6828 void TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp, bool Manual) // open to trains
6829 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6830 {
6831  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers," +
6832  AnsiString(HLoc) + "," + AnsiString(VLoc));
6833  if(!IsLCAtHV(29, HLoc, VLoc))
6834  {
6835  throw Exception("Error, Wrong track type in PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers");
6836  }
6837  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
6838  {
6839  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers");
6840  }
6841 // check for adjacent LCs & if so open (to trains)
6842  if(BaseElementSpeedTag == 1) // hor track element
6843  {
6844  // find topmost LC, opening them all (to trains) in turn
6845  int UpStep = 0;
6846  while(IsLCAtHV(30, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6847  {
6848  UpStep--;
6849  }
6850  UpStep++;
6851  // now find bottommost LC, opening them all (to trains) in turn
6852  int DownStep = 1;
6853  while(IsLCAtHV(31, HLoc, (VLoc + DownStep)))
6854  {
6855  DownStep++;
6856  }
6857  DownStep--;
6858  // now plot graphics, UpStep is smallest & DownStep largest
6859  if(UpStep == DownStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6860  {
6861  if(!Manual)
6862  {
6863  Disp->PlotOutput(179, HLoc * 16, VLoc * 16, RailGraphics->LCBothHor);
6864  }
6865  else
6866  {
6867  Disp->PlotOutput(271, HLoc * 16, VLoc * 16, RailGraphics->LCBothHorMan);
6868  }
6869  }
6870  else if((DownStep - UpStep) == 1) // double track, no need for any plain LC graphics
6871  {
6872  if(!Manual)
6873  {
6874  Disp->PlotOutput(180, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6875  Disp->PlotOutput(181, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6876  }
6877  else
6878  {
6879  Disp->PlotOutput(272, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6880  Disp->PlotOutput(273, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6881  }
6882  }
6883  else // at least one plain graphic
6884  {
6885  if(!Manual)
6886  {
6887  Disp->PlotOutput(182, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6888  Disp->PlotOutput(183, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6889  for(int x = (UpStep + 1); x < DownStep; x++)
6890  {
6891  Disp->PlotOutput(184, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlain);
6892  }
6893  }
6894  else
6895  {
6896  Disp->PlotOutput(274, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6897  Disp->PlotOutput(275, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6898  for(int x = (UpStep + 1); x < DownStep; x++)
6899  {
6900  Disp->PlotOutput(276, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlainMan);
6901  }
6902  }
6903  }
6904  // set markers
6905  for(int x = UpStep; x <= DownStep; x++)
6906  {
6907  GetInactiveTrackElementFromTrackMap(3, HLoc, (VLoc + x)).LCPlotted = true; // plotted
6908  }
6909  Display->Update();
6910  Utilities->CallLogPop(1944);
6911  return;
6912  }
6913 
6914  else // ver track element
6915  {
6916  // find leftmost LC, opening them all (to trains) in turn
6917  int LStep = 0;
6918  while(IsLCAtHV(32, (HLoc + LStep), VLoc))
6919  {
6920  LStep--;
6921  }
6922  LStep++;
6923  // now find rightmost LC, opening them all (to trains) in turn
6924  int RStep = 1;
6925  while(IsLCAtHV(33, (HLoc + RStep), VLoc))
6926  {
6927  RStep++;
6928  }
6929  RStep--;
6930  // now plot graphics, LStep is smallest & RStep largest
6931  if(LStep == RStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6932  {
6933  if(!Manual)
6934  {
6935  Disp->PlotOutput(185, HLoc * 16, VLoc * 16, RailGraphics->LCBothVer);
6936  }
6937  else
6938  {
6939  Disp->PlotOutput(277, HLoc * 16, VLoc * 16, RailGraphics->LCBothVerMan);
6940  }
6941  }
6942  else if((RStep - LStep) == 1) // double track, no need for any plain LC graphics
6943  {
6944  if(!Manual)
6945  {
6946  Disp->PlotOutput(186, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6947  Disp->PlotOutput(187, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6948  }
6949  else
6950  {
6951  Disp->PlotOutput(278, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6952  Disp->PlotOutput(279, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6953  }
6954  }
6955  else // at least one plain graphic
6956  {
6957  if(!Manual)
6958  {
6959  Disp->PlotOutput(188, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6960  Disp->PlotOutput(189, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6961  for(int x = (LStep + 1); x < RStep; x++)
6962  {
6963  Disp->PlotOutput(190, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlain);
6964  }
6965  }
6966  else
6967  {
6968  Disp->PlotOutput(280, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6969  Disp->PlotOutput(281, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6970  for(int x = (LStep + 1); x < RStep; x++)
6971  {
6972  Disp->PlotOutput(282, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlainMan);
6973  }
6974  }
6975  }
6976  // set markers
6977  for(int x = LStep; x <= RStep; x++)
6978  {
6979  GetInactiveTrackElementFromTrackMap(4, (HLoc + x), VLoc).LCPlotted = true; // plotted
6980  }
6981  Disp->Update();
6982  Utilities->CallLogPop(1945);
6983  return;
6984  }
6985 }
6986 
6987 // ---------------------------------------------------------------------------
6988 
6989 void TTrack::PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp) // closed to trains
6990 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6991 {
6992  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotRaisedLinkedLevelCrossingBarriers," + AnsiString(HLoc) + "," +
6993  AnsiString(VLoc));
6994  if(!IsLCAtHV(9, HLoc, VLoc))
6995  {
6996  throw Exception("Error, Wrong track type in PlotAndRaiseLevelCrossingBarriers");
6997  }
6998  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
6999  {
7000  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotAndRaiseLevelCrossingBarriers");
7001  }
7002 // check for adjacent LCs & if so close (to trains)
7003  if(BaseElementSpeedTag == 1) // hor track element
7004  {
7005  // find topmost LC, closing them all (to trains) in turn
7006  int UpStep = 0;
7007  while(IsLCAtHV(10, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7008  {
7009  UpStep--;
7010  }
7011  UpStep++;
7012  // now find bottommost LC, opening them all (to trains) in turn
7013  int DownStep = 1;
7014  while(IsLCAtHV(11, HLoc, (VLoc + DownStep)))
7015  {
7016  DownStep++;
7017  }
7018  DownStep--;
7019  // now plot graphics, UpStep is smallest & DownStep largest
7020  for(int x = UpStep; x < (DownStep + 1); x++)
7021  {
7022  Disp->PlotOutput(168, HLoc * 16, (VLoc + x) * 16, RailGraphics->bmSolidBgnd);
7023  Disp->PlotOutput(169, HLoc * 16, (VLoc + x) * 16, RailGraphics->gl1);
7024  Disp->PlotOutput(170, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCBothVer);
7025  }
7026  Disp->Update();
7027  Utilities->CallLogPop(1959);
7028  return;
7029  }
7030 
7031  else // ver track element
7032  {
7033  // find leftmost LC, closing them all (to trains) in turn
7034  int LStep = 0;
7035  while(IsLCAtHV(12, (HLoc + LStep), VLoc))
7036  {
7037  LStep--;
7038  }
7039  LStep++;
7040  // now find rightmost LC, opening them all (to trains) in turn
7041  int RStep = 1;
7042  while(IsLCAtHV(13, (HLoc + RStep), VLoc))
7043  {
7044  RStep++;
7045  }
7046  RStep--;
7047  // now plot graphics, LStep is smallest & RStep largest
7048  for(int x = LStep; x < (RStep + 1); x++)
7049  {
7050  Disp->PlotOutput(171, (HLoc + x) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7051  Disp->PlotOutput(172, (HLoc + x) * 16, VLoc * 16, RailGraphics->gl2);
7052  Disp->PlotOutput(173, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCBothHor);
7053  }
7054  Disp->Update();
7055  Utilities->CallLogPop(1960);
7056  return;
7057  }
7058 }
7059 
7060 // ---------------------------------------------------------------------------
7061 
7062 void TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
7063 // closed to trains
7064 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
7065 {
7066  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers," +
7067  AnsiString(HLoc) + "," + AnsiString(VLoc));
7068  if(!IsLCAtHV(34, HLoc, VLoc))
7069  {
7070  throw Exception("Error, Wrong track type in PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers");
7071  }
7072  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
7073  {
7074  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers");
7075  }
7076  TTrackElement TE;
7077 
7078 // check for adjacent LCs & if so close (to trains)
7079  if(BaseElementSpeedTag == 1) // hor track element
7080  {
7081  // find topmost LC, closing them all (to trains) in turn
7082  int UpStep = 0;
7083  while(IsLCAtHV(35, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7084  {
7085  UpStep--;
7086  }
7087  UpStep++;
7088  // now find bottommost LC, opening them all (to trains) in turn
7089  int DownStep = 1;
7090  while(IsLCAtHV(36, HLoc, (VLoc + DownStep)))
7091  {
7092  DownStep++;
7093  }
7094  DownStep--;
7095  // now plot graphics, UpStep is smallest & DownStep largest
7096  for(int x = UpStep; x <= DownStep; x++)
7097  {
7098  Disp->PlotOutput(191, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCBothVer);
7099  GetInactiveTrackElementFromTrackMap(1, HLoc, (VLoc + x)).LCPlotted = true; // plotted
7100  }
7101  Display->Update();
7102  Utilities->CallLogPop(1946);
7103  return;
7104  }
7105 
7106  else // ver track element
7107  {
7108  // find leftmost LC, closing them all (to trains) in turn
7109  int LStep = 0;
7110  while(IsLCAtHV(37, (HLoc + LStep), VLoc))
7111  {
7112  LStep--;
7113  }
7114  LStep++;
7115  // now find rightmost LC, opening them all (to trains) in turn
7116  int RStep = 1;
7117  while(IsLCAtHV(38, (HLoc + RStep), VLoc))
7118  {
7119  RStep++;
7120  }
7121  RStep--;
7122  // now plot graphics, LStep is smallest & RStep largest
7123  for(int x = LStep; x <= RStep; x++)
7124  {
7125  Disp->PlotOutput(192, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCBothHor);
7126  GetInactiveTrackElementFromTrackMap(2, (HLoc + x), VLoc).LCPlotted = true; // plotted
7127  }
7128  Display->Update();
7129  Utilities->CallLogPop(1947);
7130  return;
7131  }
7132 }
7133 
7134 // ---------------------------------------------------------------------------
7135 
7136 void TTrack::PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp)
7137 {
7138  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotBaseElementsOnly," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7139  Graphics::TBitmap *RouteGraphic;
7140  Graphics::TBitmap *BaseGraphic = RailGraphics->gl1;
7141 
7142  if(BaseElementSpeedTag == 1)
7143  {
7144  if(TypeOfRoute == 1)
7145  {
7146  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[0];
7147  }
7148  else if(TypeOfRoute == 0)
7149  {
7150  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[0];
7151  }
7152  else //manual
7153  {
7154  RouteGraphic = BaseGraphic;
7155  }
7156  if(State == Raising)
7157  {
7158  RouteGraphic = BaseGraphic;
7159  }
7160  }
7161  else
7162  {
7163  BaseGraphic = RailGraphics->gl2;
7164  if(TypeOfRoute == 1)
7165  {
7166  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[1];
7167  }
7168  else if(TypeOfRoute == 0)
7169  {
7170  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[1];
7171  }
7172  else
7173  {
7174  RouteGraphic = BaseGraphic; //manual
7175  }
7176  if(State == Raising)
7177  {
7178  RouteGraphic = BaseGraphic;
7179  }
7180  }
7181  int UpStep = 0;
7182 
7183  while(IsLCAtHV(14, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7184  {
7185  Disp->PlotOutput(174, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
7186  if(UpStep == 0)
7187  {
7188  Disp->PlotOutput(175, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
7189  }
7190  else
7191  {
7192  Disp->PlotOutput(234, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
7193  }
7194  UpStep--;
7195  }
7196 // now find bottommost LC, opening them all (to trains) in turn
7197  int DownStep = 1;
7198 
7199  while(IsLCAtHV(15, HLoc, (VLoc + DownStep)))
7200  {
7201  Disp->PlotOutput(176, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
7202  Disp->PlotOutput(177, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
7203  DownStep++;
7204  }
7205  int LeftStep = 0;
7206 
7207  while(IsLCAtHV(16, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
7208  {
7209  Disp->PlotOutput(233, (HLoc + LeftStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7210  if(LeftStep == 0)
7211  {
7212  Disp->PlotOutput(235, (HLoc + LeftStep) * 16, VLoc * 16, RouteGraphic);
7213  }
7214  else
7215  {
7216  Disp->PlotOutput(236, (HLoc + LeftStep) * 16, VLoc * 16, BaseGraphic);
7217  }
7218  LeftStep--;
7219  }
7220 // now find rightmost LC, opening them all (to trains) in turn
7221  int RightStep = 1;
7222 
7223  while(IsLCAtHV(17, (HLoc + RightStep), VLoc))
7224  {
7225  Disp->PlotOutput(237, (HLoc + RightStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7226  Disp->PlotOutput(238, (HLoc + RightStep) * 16, VLoc * 16, BaseGraphic);
7227  RightStep++;
7228  }
7229  Disp->Update();
7230  Utilities->CallLogPop(1914);
7231 }
7232 
7233 // ---------------------------------------------------------------------------
7234 
7235 bool TTrack::IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc) // returns true only if fully down
7236 {
7237 // return false for no LC there, flashing or a closed (to trains) LC
7238  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsLCBarrierDownAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7239  bool FoundFlag;
7240  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(21, HLoc, VLoc, FoundFlag);
7241 
7242  if(!FoundFlag)
7243  {
7244  Utilities->CallLogPop(1898);
7245  return(false);
7246  }
7247  if(InactiveTrackElementAt(100, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7248  {
7249  Utilities->CallLogPop(1899);
7250  return(false);
7251  }
7252  if(InactiveTrackElementAt(103, IMPair.first).Attribute == 1)
7253  {
7254  Utilities->CallLogPop(1900);
7255  return(true);
7256  }
7257  Utilities->CallLogPop(1901);
7258  return(false);
7259 }
7260 
7261 // ---------------------------------------------------------------------------
7262 
7263 bool TTrack::IsLCBarrierUpAtHV(int Caller, int HLoc, int VLoc) // returns true only if fully up
7264 {
7265 // return false for no LC there, flashing LC or open (to trains) LC
7266  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierUpLCAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7267  bool FoundFlag;
7268  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(24, HLoc, VLoc, FoundFlag);
7269 
7270  if(!FoundFlag)
7271  {
7272  Utilities->CallLogPop(1922);
7273  return(false);
7274  }
7275  if(InactiveTrackElementAt(110, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7276  {
7277  Utilities->CallLogPop(1923);
7278  return(false);
7279  }
7280  if(InactiveTrackElementAt(111, IMPair.first).Attribute == 0)
7281  {
7282  Utilities->CallLogPop(1924);
7283  return(true);
7284  }
7285  Utilities->CallLogPop(1925);
7286  return(false);
7287 }
7288 
7289 // ---------------------------------------------------------------------------
7290 
7291 bool TTrack::IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
7292 {
7293 // return true for barrier in process of moving
7294  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierFlashingAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7295  bool FoundFlag;
7296  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(25, HLoc, VLoc, FoundFlag);
7297 
7298  if(!FoundFlag)
7299  {
7300  Utilities->CallLogPop(1918);
7301  return(false);
7302  }
7303  if(InactiveTrackElementAt(112, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7304  {
7305  Utilities->CallLogPop(1919);
7306  return(false);
7307  }
7308  if(InactiveTrackElementAt(113, IMPair.first).Attribute == 2)
7309  {
7310  Utilities->CallLogPop(1920);
7311  return(true);
7312  }
7313  Utilities->CallLogPop(1921);
7314  return(false);
7315 }
7316 
7317 // ---------------------------------------------------------------------------
7318 
7319 bool TTrack::IsLCAtHV(int Caller, int HLoc, int VLoc)
7320 {
7321 // return true for an LC at H&V
7322  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsLCAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7323  bool FoundFlag;
7324  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(22, HLoc, VLoc, FoundFlag);
7325 
7326  if(!FoundFlag)
7327  {
7328  Utilities->CallLogPop(1902);
7329  return(false);
7330  }
7331  if(InactiveTrackElementAt(101, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7332  {
7333  Utilities->CallLogPop(1903);
7334  return(false);
7335  }
7336  Utilities->CallLogPop(1904);
7337  return(true);
7338 }
7339 
7340 // ---------------------------------------------------------------------------
7341 
7342 void TTrack::SetLCAttributeAtHV(int Caller, int HLoc, int VLoc, int Attr)
7343 {
7344  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLCAttributeAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
7345  AnsiString(Attr));
7346  bool FoundFlag;
7347  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(23, HLoc, VLoc, FoundFlag);
7348 
7349  if(!FoundFlag)
7350  {
7351  throw Exception("Element not found in LowerLCBarriersAtHV " + AnsiString(HLoc) + "," + AnsiString(VLoc));
7352  }
7353  if(InactiveTrackElementAt(102, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7354  {
7355  throw Exception("Element not a level crossing in LowerLCBarriersAtHV " + AnsiString(HLoc) + "," + AnsiString(VLoc));
7356  }
7357  InactiveTrackElementAt(104, IMPair.first).Attribute = Attr;
7358  Utilities->CallLogPop(1905);
7359  return;
7360 }
7361 
7362 // ---------------------------------------------------------------------------
7363 
7365 {
7366  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetLevelCrossings");
7367  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
7368  {
7369  TTrackElement InactiveTrackElement = InactiveTrackElementAt(140, x);
7370  if(InactiveTrackElement.TrackType == LevelCrossing)
7371  {
7372  InactiveTrackElementAt(141, x).Attribute = 0;
7373  // though this only resets the attributes the LC will display correctly when call Clearand.. in BaseMode
7374  }
7375  }
7376  Utilities->CallLogPop(1913);
7377  return;
7378 }
7379 
7380 // ---------------------------------------------------------------------------
7381 
7382 bool TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector, bool &TrainPresent)
7383 {
7384 // return true if there is either a route set or being set on any element or a train on any element
7385  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AnyLinkedLevelCrossingElementsWithRoutesOrTrains," + AnsiString(HLoc) +
7386  "," + AnsiString(VLoc));
7387 
7388  THVPair TrackMapKeyPair;
7389  TTrack::TTrackMapIterator TrackMapPtr;
7390  int DummyRouteNumber;
7391 
7392  TrainPresent = false;
7393 // find topmost LC, checking each for routes & trains
7394  int UpStep = 0;
7395 
7396  while(IsLCAtHV(25, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7397  {
7398  TrackMapKeyPair.first = HLoc;
7399  TrackMapKeyPair.second = VLoc + UpStep;
7400  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7401  if(AllRoutes->GetRouteTypeAndNumber(20, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7402  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7403  {
7404  Utilities->CallLogPop(1932);
7405  return(true);
7406  }
7407  if(TrackElementAt(867, TrackMapPtr->second).TrainIDOnElement != -1)
7408  {
7409  TrainPresent = true;
7410  Utilities->CallLogPop(1933);
7411  return(true);
7412  }
7413  if(LCInSearchVector(0, HLoc, (VLoc + UpStep), SearchVector)) //route being set, added at v2.8.0
7414  {
7415  Utilities->CallLogPop(2274);
7416  return(true);
7417  }
7418  UpStep--;
7419  }
7420 // now find bottommost LC, opening them all (to trains) in turn
7421  int DownStep = 1;
7422 
7423  while(IsLCAtHV(26, HLoc, (VLoc + DownStep)))
7424  {
7425  TrackMapKeyPair.first = HLoc;
7426  TrackMapKeyPair.second = VLoc + DownStep;
7427  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7428  if(AllRoutes->GetRouteTypeAndNumber(21, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7429  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7430  {
7431  Utilities->CallLogPop(1934);
7432  return(true);
7433  }
7434  if(TrackElementAt(868, TrackMapPtr->second).TrainIDOnElement != -1)
7435  {
7436  TrainPresent = true;
7437  Utilities->CallLogPop(1935);
7438  return(true);
7439  }
7440  if(LCInSearchVector(1, HLoc, (VLoc + DownStep), SearchVector)) //route being set, added at v2.8.0
7441  {
7442  Utilities->CallLogPop(2275);
7443  return(true);
7444  }
7445  DownStep++;
7446  }
7447 // find leftmost LC
7448  int LeftStep = 0;
7449 
7450  while(IsLCAtHV(27, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
7451  {
7452  TrackMapKeyPair.first = HLoc + LeftStep;
7453  TrackMapKeyPair.second = VLoc;
7454  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7455  if(AllRoutes->GetRouteTypeAndNumber(22, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7456  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7457  {
7458  Utilities->CallLogPop(1936);
7459  return(true);
7460  }
7461  if(TrackElementAt(869, TrackMapPtr->second).TrainIDOnElement != -1)
7462  {
7463  TrainPresent = true;
7464  Utilities->CallLogPop(1937);
7465  return(true);
7466  }
7467  if(LCInSearchVector(2, (HLoc + LeftStep), VLoc, SearchVector)) //route being set, added at v2.8.0
7468  {
7469  Utilities->CallLogPop(2276);
7470  return(true);
7471  }
7472  LeftStep--;
7473  }
7474 // now find rightmost LC, opening them all (to trains) in turn
7475  int RightStep = 1;
7476 
7477  while(IsLCAtHV(28, (HLoc + RightStep), VLoc))
7478  {
7479  TrackMapKeyPair.first = HLoc + RightStep;
7480  TrackMapKeyPair.second = VLoc;
7481  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7482  if(AllRoutes->GetRouteTypeAndNumber(23, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7483  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7484  {
7485  Utilities->CallLogPop(1938);
7486  return(true);
7487  }
7488  if(TrackElementAt(870, TrackMapPtr->second).TrainIDOnElement != -1)
7489  {
7490  TrainPresent = true;
7491  Utilities->CallLogPop(1939);
7492  return(true);
7493  }
7494  if(LCInSearchVector(3, (HLoc + RightStep), VLoc, SearchVector)) //route being set, added at v2.8.0
7495  {
7496  Utilities->CallLogPop(2277);
7497  return(true);
7498  }
7499  RightStep++;
7500  }
7501  Utilities->CallLogPop(1940);
7502  return(false);
7503 }
7504 
7505 // ---------------------------------------------------------------------------
7506 
7507 bool TTrack::LCInSearchVector(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector) //added at v2.8.0
7508 {
7509  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LCInSearchVector," + HLoc + "," + VLoc);
7510  for(unsigned int x = 0; x < SearchVector.size(); x++)
7511  {
7512  if((TrackElementAt(1019, SearchVector.at(x).GetTrackVectorPosition()).HLoc == HLoc) && (TrackElementAt(1020, SearchVector.at(x).GetTrackVectorPosition()).VLoc == VLoc))
7513  {
7514  Utilities->CallLogPop(2278);
7515  return(true);
7516  }
7517  }
7518  Utilities->CallLogPop(2279);
7519  return(false);
7520 }
7521 
7522 // ---------------------------------------------------------------------------
7523 
7524 void TTrack::PlotSmallFlashingLinkedLevelCrossings(int Caller, int HLoc, int VLoc, Graphics::TBitmap *GraphicPtr, TDisplay *Disp)
7525 {
7526  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallFlashingLinkedLevelCrossings," +
7527  AnsiString(HLoc) + "," + AnsiString(VLoc));
7528  if(!IsLCAtHV(60, HLoc, VLoc))
7529  {
7530  throw Exception("PlotSmallFlashingLinkedLevelCrossings");
7531  }
7532 
7533 // check for adjacent LCs
7534  // find topmost LC
7535  int UpStep = 0;
7536  while(IsLCAtHV(61, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7537  {
7538  UpStep--;
7539  }
7540  UpStep++;
7541  // now find bottommost LC, opening them all (to trains) in turn
7542  int DownStep = 1;
7543  while(IsLCAtHV(62, HLoc, (VLoc + DownStep)))
7544  {
7545  DownStep++;
7546  }
7547  DownStep--;
7548  // now plot graphics, UpStep is smallest & DownStep largest
7549  for(int x = UpStep; x <= DownStep; x++)
7550  {
7551  Disp->PlotSmallOutput(24, HLoc * 4, (VLoc + x) * 4, GraphicPtr);
7552  }
7553 
7554  // find leftmost LC, closing them all (to trains) in turn
7555  int LStep = 0;
7556  while(IsLCAtHV(63, (HLoc + LStep), VLoc))
7557  {
7558  LStep--;
7559  }
7560  LStep++;
7561  // now find rightmost LC, opening them all (to trains) in turn
7562  int RStep = 1;
7563  while(IsLCAtHV(64, (HLoc + RStep), VLoc))
7564  {
7565  RStep++;
7566  }
7567  RStep--;
7568  // now plot graphics, LStep is smallest & RStep largest
7569  for(int x = LStep; x <= RStep; x++)
7570  {
7571  Disp->PlotSmallOutput(25, (HLoc + x) * 4, VLoc * 4, GraphicPtr);
7572  }
7573  Display->Update();
7574  Utilities->CallLogPop(2315);
7575  return;
7576 }
7577 
7578 // ---------------------------------------------------------------------------
7579 
7580 Graphics::TBitmap *TTrack::GetFilletGraphic(int Caller, TTrackElement TrackElement)
7581 {
7582  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFilletGraphic," + TrackElement.LogTrack(4));
7583  if(TrackElement.TrackType != Points)
7584  {
7585  throw Exception("Error, Wrong track type in GetFilletGraphic");
7586  }
7587  if(TrackElement.SpeedTag < 28)
7588  {
7589  Utilities->CallLogPop(521);
7590  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]);
7591  }
7592  else if(TrackElement.SpeedTag < 132)
7593  {
7594  Utilities->CallLogPop(522);
7595 // Utilities->CallLogPop callers 523 to 534 inc used to test pop failure
7596  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]);
7597  }
7598  else
7599  {
7600  Utilities->CallLogPop(1537);
7601  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]);
7602  }
7603 }
7604 
7605 // ---------------------------------------------------------------------------
7606 
7608 {
7609  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAllTrainIDElements");
7610  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
7611  {
7612  TrackElementAt(1351, x).TrainIDOnElement = -1;
7615  }
7616  Utilities->CallLogPop(1342);
7617 }
7618 
7619 // ---------------------------------------------------------------------------
7620 
7621 void TTrack::GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
7622 /*
7623  Converts the screen position to the true (without offsets) HLoc, VLoc 16 x 16 square that the screen position lies within
7624 */
7625 {
7626  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackLocsFromScreenPos," + AnsiString(ScreenPosH) + "," +
7627  AnsiString(ScreenPosV));
7628  HLoc = div(ScreenPosH, 16).quot + Display->DisplayOffsetH;
7629  VLoc = div(ScreenPosV, 16).quot + Display->DisplayOffsetV;
7630 // Utilities->CallLogPop callers 523 to 534 inc used to test pop failure
7631  Utilities->CallLogPop(535);
7632 }
7633 
7634 // ---------------------------------------------------------------------------
7635 
7636 void TTrack::GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
7637 /*
7638  Converts the screen position to the true (without offsets) position
7639 */
7640 {
7641  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTruePositionsFromScreenPos," + AnsiString(ScreenPosH) + "," +
7642  AnsiString(ScreenPosV));
7643  HPos = ScreenPosH + (Display->DisplayOffsetH * 16);
7644  VPos = ScreenPosV + (Display->DisplayOffsetV * 16);
7645  Utilities->CallLogPop(536);
7646 }
7647 
7648 // ---------------------------------------------------------------------------
7649 
7650 void TTrack::GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
7651 {
7652  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetScreenPositionsFromTruePos," + AnsiString(HPosTrue) + "," +
7653  AnsiString(VPosTrue));
7654  ScreenPosH = HPosTrue - (Display->DisplayOffsetH * 16);
7655  ScreenPosV = VPosTrue - (Display->DisplayOffsetV * 16);
7656  Utilities->CallLogPop(537);
7657 }
7658 
7659 // ---------------------------------------------------------------------------
7660 
7661 void TTrack::CheckMapAndTrack(int Caller) // test
7662 {
7663  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndTrack");
7664  int Zeroes = 0;
7665  bool FoundFlag;
7666 
7667  for(unsigned int a = 0; a < TrackVector.size(); a++)
7668  {
7669  TTrackElement CheckElement = Track->TrackElementAt(1354, a);
7670  if(CheckElement.SpeedTag == 0)
7671  {
7672  Zeroes++; // zeroed elements not saved in map
7673  }
7674  else
7675  {
7676  int MapVecPos = GetVectorPositionFromTrackMap(16, CheckElement.HLoc, CheckElement.VLoc, FoundFlag);
7677  if(!FoundFlag)
7678  {
7679  throw Exception("CheckMapAndTrack Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
7680  " in TrackMap, Caller=" + (AnsiString)Caller);
7681  }
7682  if(MapVecPos != (int)a)
7683  {
7684  throw Exception("CheckMapAndTrack Error - MapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
7685  (AnsiString)CheckElement.VLoc + " Map value=" + (AnsiString)MapVecPos + " TrackVectorPos value=" + (AnsiString)a + " Caller=" +
7686  (AnsiString)Caller);
7687  }
7688  }
7689  }
7690  if(TrackVector.size() != (TrackMap.size() + Zeroes))
7691  {
7692  throw Exception("CheckMapAndTrack Error - Map Size=" + (AnsiString)TrackVector.size() + " TrackVectorSize=" + (AnsiString)TrackVector.size() +
7693  " Caller=" + (AnsiString)Caller);
7694  }
7695  Utilities->CallLogPop(538);
7696  return;
7697 }
7698 
7699 // ---------------------------------------------------------------------------
7700 
7701 void TTrack::CheckMapAndInactiveTrack(int Caller) // test
7702 {
7703  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndInactiveTrack");
7704  bool FoundFlag;
7705  TIMPair InactivePair;
7706 
7707  for(unsigned int a = 0; a < InactiveTrackVector.size(); a++)
7708  {
7709  TTrackElement CheckElement = Track->InactiveTrackElementAt(142, a);
7710  InactivePair = GetVectorPositionsFromInactiveTrackMap(7, CheckElement.HLoc, CheckElement.VLoc, FoundFlag);
7711  if(!FoundFlag)
7712  {
7713  throw Exception("CheckMapAndInactiveTrack Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
7714  " in InactiveMap, Caller=" + (AnsiString)Caller);
7715  }
7716  if((InactivePair.first != a) && (InactivePair.second != a))
7717  {
7718  throw Exception("CheckMapAndInactiveTrack Error - InactiveMapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
7719  (AnsiString)CheckElement.VLoc + " Inactive Map values=" + (AnsiString)InactivePair.first + " and " + (AnsiString)InactivePair.second +
7720  " InactiveTrackVectorPos value=" + (AnsiString)a + " Caller=" + (AnsiString)Caller);
7721  }
7722  }
7723  if(InactiveTrackVector.size() != InactiveTrack2MultiMap.size())
7724  {
7725  throw Exception("CheckMapAndInactiveTrack Error - Map Size=" + (AnsiString)TrackVector.size() + " TrackVectorSize=" + (AnsiString)TrackVector.size() +
7726  " Caller=" + (AnsiString)Caller);
7727  }
7728  Utilities->CallLogPop(539);
7729 }
7730 
7731 // ---------------------------------------------------------------------------
7732 
7733 void TTrack::CheckGapMap(int Caller) // test
7734 {
7735  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckGapMap");
7736  int Position1, Position2;
7737  TTrackElement TrackElement1, TrackElement2;
7738  TGapMapIterator GapMapPtr;
7739 
7740  if(!GapMap.empty())
7741  {
7742  for(GapMapPtr = GapMap.begin(); GapMapPtr != GapMap.end(); GapMapPtr++)
7743  {
7744  int HLoc1 = GapMapPtr->first.first;
7745  int VLoc1 = GapMapPtr->first.second;
7746  int HLoc2 = GapMapPtr->second.first;
7747  int VLoc2 = GapMapPtr->second.second;
7748  if(!FindNonPlatformMatch(14, HLoc1, VLoc1, Position1, TrackElement1))
7749  {
7750  throw Exception("Failed to find H & V for gap1, GapMap in error");
7751  }
7752  if(!FindNonPlatformMatch(15, HLoc2, VLoc2, Position2, TrackElement2))
7753  {
7754  throw Exception("Failed to find H & V for gap2, GapMap in error");
7755  }
7756  if(TrackElementAt(17, Position1).TrackType != GapJump)
7757  {
7758  throw Exception("Element at Pos1 not a gap, GapMap in error");
7759  }
7760  if(TrackElementAt(18, Position2).TrackType != GapJump)
7761  {
7762  throw Exception("Element at Pos2 not a gap, GapMap in error");
7763  }
7764  }
7765  }
7766  unsigned int GapCount = 0;
7767 
7768  for(unsigned int a = 0; a < TrackVector.size(); a++)
7769  {
7770  TTrackElement CheckElement = Track->TrackElementAt(1355, a);
7771  if(CheckElement.TrackType == GapJump)
7772  {
7773  GapCount++;
7774  }
7775  }
7776  if((GapMap.size() * 2) != GapCount)
7777  {
7778  throw Exception("GapMap Error - Map Size * 2 =" + (AnsiString)(GapMap.size() * 2) + " GapCount=" + (AnsiString)GapCount + " Caller=" +
7779  (AnsiString)Caller);
7780  }
7781  Utilities->CallLogPop(540);
7782 }
7783 
7784 // ---------------------------------------------------------------------------
7785 
7786 void TTrack::SetElementID(int Caller, TTrackElement &TrackElement)
7787 {
7788  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetElementID," + TrackElement.LogTrack(5));
7789  if((TrackElement.HLoc == -2000000000) || (TrackElement.VLoc == -2000000000))
7790  {
7791  if(TrackFinished)
7792  {
7793  throw Exception("Error - TrackFinished with erase element still present");
7794  }
7795  Utilities->CallLogPop(541);
7796  return; // erased element, can't set ID
7797  }
7798  AnsiString IDString;
7799 
7800  if(TrackElement.HLoc < 0)
7801  {
7802  IDString = "N" + AnsiString(abs(TrackElement.HLoc)) + "-";
7803  }
7804  else
7805  {
7806  IDString = AnsiString(TrackElement.HLoc) + "-";
7807  }
7808  if(TrackElement.VLoc < 0)
7809  {
7810  IDString += "N" + AnsiString(abs(TrackElement.VLoc));
7811  }
7812  else
7813  {
7814  IDString += AnsiString(TrackElement.VLoc);
7815  }
7816  TrackElement.ElementID = IDString;
7817  Utilities->CallLogPop(542);
7818 }
7819 
7820 // ---------------------------------------------------------------------------
7821 
7822 int TTrack::GetTrackVectorPositionFromString(int Caller, AnsiString String, bool GiveMessages)
7823 {
7824 // e.g. "8-13", "00008-13", "N43-N127", etc
7825  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackVectorPositionFromString, + String");
7826  int DelimPos;
7827 
7828  for(int x = 1; x < String.Length() + 1; x++)
7829  {
7830  if(String.IsDelimiter("-", x))
7831  {
7832  DelimPos = x;
7833  break;
7834  }
7835  if(x == String.Length())
7836  {
7837  if(GiveMessages)
7838  {
7839  ShowMessage("Error in track element identifier: <" + String + "> - no delimiter");
7840  }
7841  Utilities->CallLogPop(543);
7842  return(-1);
7843  }
7844  }
7845  if(DelimPos == 1)
7846  {
7847  if(GiveMessages)
7848  {
7849  ShowMessage("Error in track element identifier: <" + String + "> - No Horizontal value");
7850  }
7851  Utilities->CallLogPop(544);
7852  return(-1);
7853  }
7854  if(DelimPos == String.Length())
7855  {
7856  if(GiveMessages)
7857  {
7858  ShowMessage("Error in track element identifier <" + String + "> - No Vertical value");
7859  }
7860  Utilities->CallLogPop(545);
7861  return(-1);
7862  }
7863  if((String[String.Length()] < '0') || (String[String.Length()] > '9'))
7864  {
7865  if(GiveMessages)
7866  {
7867  ShowMessage("Error in track element identifier <" + String + "> - Last value is not a number");
7868  }
7869  Utilities->CallLogPop(1508);
7870  return(-1);
7871  }
7872  int HLoc, VLoc;
7873 
7874  if(String.SubString(1, 1) != "N")
7875  {
7876  for(int x = 1; x < DelimPos; x++)
7877  {
7878  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
7879  {
7880  if(GiveMessages)
7881  {
7882  ShowMessage("Invalid character in Horizontal value in track element identifier: <" + String + ">");
7883  }
7884  Utilities->CallLogPop(546);
7885  return(-1);
7886  }
7887  }
7888  }
7889  if(String.SubString(1, 1) == "N")
7890  {
7891  for(int x = 2; x < DelimPos; x++)
7892  {
7893  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
7894  {
7895  if(GiveMessages)
7896  {
7897  ShowMessage("Invalid character in Horizontal value in track element identifier: <" + String + ">");
7898  }
7899  Utilities->CallLogPop(763);
7900  return(-1);
7901  }
7902  }
7903  }
7904  if(String.SubString(1, 1) == "N")
7905  {
7906  HLoc = -(String.SubString(2, DelimPos - 2).ToInt());
7907  }
7908  else
7909  {
7910  HLoc = String.SubString(1, DelimPos - 1).ToInt();
7911  }
7912  if(String.SubString(DelimPos + 1, 1) != "N")
7913  {
7914  for(int x = DelimPos + 1; x < String.Length() + 1; x++)
7915  {
7916  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
7917  {
7918  if(GiveMessages)
7919  {
7920  ShowMessage("Invalid character in Vertical value in track element identifier: <" + String + ">");
7921  }
7922  Utilities->CallLogPop(547);
7923  return(-1);
7924  }
7925  }
7926  }
7927  if(String.SubString(DelimPos + 1, 1) == "N")
7928  {
7929  for(int x = DelimPos + 2; x < String.Length() + 1; x++)
7930  {
7931  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
7932  {
7933  if(GiveMessages)
7934  {
7935  ShowMessage("Invalid character in Vertical value in track element identifier: <" + String + ">");
7936  }
7937  Utilities->CallLogPop(764);
7938  return(-1);
7939  }
7940  }
7941  }
7942  if(String.SubString(DelimPos + 1, 1) == "N")
7943  {
7944  VLoc = -(String.SubString(DelimPos + 2, String.Length() - DelimPos - 1).ToInt());
7945  }
7946  else
7947  {
7948  VLoc = String.SubString(DelimPos + 1, String.Length() - DelimPos).ToInt();
7949  }
7950  THVPair HVPair(HLoc, VLoc);
7951  TTrackMapIterator TrackMapPtr;
7952 
7953  TrackMapPtr = TrackMap.find(HVPair);
7954  if(TrackMapPtr == TrackMap.end())
7955  {
7956  if(GiveMessages)
7957  {
7958  ShowMessage("No track element corresponding to track element identifier: <" + String + ">");
7959  }
7960  Utilities->CallLogPop(548);
7961  return(-1);
7962  }
7963  Utilities->CallLogPop(549);
7964  return(TrackMapPtr->second);
7965 }
7966 
7967 // ---------------------------------------------------------------------------
7968 
7969 bool TTrack::CheckFootCrossingLinks(int Caller, TTrackElement &TrackElement)
7970 /*
7971  True for linked properly at both ends
7972 */
7973 {
7974  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckFootCrossingLinks," + AnsiString(TrackElement.HLoc) + "," +
7975  AnsiString(TrackElement.VLoc) + "," + AnsiString(TrackElement.SpeedTag));
7976  int HLoc = TrackElement.HLoc;
7977  int VLoc = TrackElement.VLoc;
7978 
7979  if((TrackElement.SpeedTag != 129) && (TrackElement.SpeedTag != 130) && (TrackElement.SpeedTag != 145) && (TrackElement.SpeedTag != 146))
7980  {
7981  Utilities->CallLogPop(1821);
7982  return(false);
7983  }
7984  if(TrackElement.SpeedTag == 129) // vertical footbridge
7985  {
7986  // check top connection
7987  if(!(InactiveMapCheck(1, HLoc, VLoc, 76) // top plat
7988  || InactiveMapCheck(2, HLoc, VLoc - 1, 96) // concourse
7989  || InactiveMapCheck(3, HLoc, VLoc - 1, 77) // bot plat
7990  || ActiveMapCheck(4, HLoc, VLoc - 1, 129))) // vert footbridge
7991  {
7992  Utilities->CallLogPop(550);
7993  return(false);
7994  }
7995  // check bottom connection
7996  else if(!(InactiveMapCheck(4, HLoc, VLoc, 77) // bot plat
7997  || InactiveMapCheck(5, HLoc, VLoc + 1, 96) // concourse
7998  || InactiveMapCheck(6, HLoc, VLoc + 1, 76) // top plat
7999  || ActiveMapCheck(1, HLoc, VLoc + 1, 129))) // vert footbridge
8000  {
8001  Utilities->CallLogPop(551);
8002  return(false);
8003  }
8004  }
8005  if(TrackElement.SpeedTag == 145) // vertical underpass
8006  {
8007  // check top connection
8008  if(!(InactiveMapCheck(13, HLoc, VLoc, 76) // top plat
8009  || InactiveMapCheck(14, HLoc, VLoc - 1, 96) // concourse
8010  || InactiveMapCheck(15, HLoc, VLoc - 1, 77) // bot plat
8011  || ActiveMapCheck(5, HLoc, VLoc - 1, 145))) // vert u'pass
8012  {
8013  Utilities->CallLogPop(2114);
8014  return(false);
8015  }
8016  // check bottom connection
8017  else if(!(InactiveMapCheck(16, HLoc, VLoc, 77) // bot plat
8018  || InactiveMapCheck(17, HLoc, VLoc + 1, 96) // concourse
8019  || InactiveMapCheck(18, HLoc, VLoc + 1, 76) // top plat
8020  || ActiveMapCheck(6, HLoc, VLoc + 1, 145))) // vert u'pass
8021  {
8022  Utilities->CallLogPop(2115);
8023  return(false);
8024  }
8025  }
8026  if(TrackElement.SpeedTag == 130) // hor footbridge
8027  {
8028  // check left connection
8029  if(!(InactiveMapCheck(19, HLoc, VLoc, 78) // left plat
8030  || InactiveMapCheck(20, HLoc - 1, VLoc, 96) // concourse
8031  || InactiveMapCheck(21, HLoc - 1, VLoc, 79) // right plat
8032  || ActiveMapCheck(2, HLoc - 1, VLoc, 130))) // hor footbridge
8033  {
8034  Utilities->CallLogPop(552);
8035  return(false);
8036  }
8037  // check right connection
8038  else if(!(InactiveMapCheck(22, HLoc, VLoc, 79) // right plat
8039  || InactiveMapCheck(23, HLoc + 1, VLoc, 96) // concourse
8040  || InactiveMapCheck(24, HLoc + 1, VLoc, 78) // left plat
8041  || ActiveMapCheck(3, HLoc + 1, VLoc, 130))) // hor footbridge
8042  {
8043  Utilities->CallLogPop(553);
8044  return(false);
8045  }
8046  }
8047  if(TrackElement.SpeedTag == 146) // hor u'pass
8048  {
8049  // check left connection
8050  if(!(InactiveMapCheck(7, HLoc, VLoc, 78) // left plat
8051  || InactiveMapCheck(8, HLoc - 1, VLoc, 96) // concourse
8052  || InactiveMapCheck(9, HLoc - 1, VLoc, 79) // right plat
8053  || ActiveMapCheck(7, HLoc - 1, VLoc, 146))) // hor u'pass
8054  {
8055  Utilities->CallLogPop(2116);
8056  return(false);
8057  }
8058  // check right connection
8059  else if(!(InactiveMapCheck(10, HLoc, VLoc, 79) // right plat
8060  || InactiveMapCheck(11, HLoc + 1, VLoc, 96) // concourse
8061  || InactiveMapCheck(12, HLoc + 1, VLoc, 78) // left plat
8062  || ActiveMapCheck(8, HLoc + 1, VLoc, 146))) // hor u'pass
8063  {
8064  Utilities->CallLogPop(2117);
8065  return(false);
8066  }
8067  }
8068  Utilities->CallLogPop(554);
8069  return(true);
8070 }
8071 
8072 // ---------------------------------------------------------------------------
8073 
8074 bool TTrack::InactiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
8075 /*
8076  return true if the SpeedTag present in the map at H & V
8077 */
8078 {
8079  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveMapCheck," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8080  AnsiString(SpeedTag));
8081  if(InactiveTrack2MultiMap.empty())
8082  {
8083  Utilities->CallLogPop(555);
8084  return(false);
8085  }
8086  THVPair HVPair(HLoc, VLoc);
8088  TInactiveTrack2MultiMapIterator HVIt1 = IMEnd, HVIt2 = IMEnd;
8089  TInactiveTrackRange HVRange = InactiveTrack2MultiMap.equal_range(HVPair);
8090 
8091  if(HVRange.first == HVRange.second)
8092  {
8093  Utilities->CallLogPop(556);
8094  return(false);
8095  }
8096  else
8097  {
8098  HVIt1 = HVRange.first;
8099  }
8100  TTrackElement Temp1, Temp2; // test
8101 
8102  Temp1 = InactiveTrackElementAt(8, HVIt1->second); // test
8103  if(--HVRange.second != HVRange.first)
8104  {
8105  HVIt2 = HVRange.second;
8106  Temp2 = InactiveTrackElementAt(9, HVIt2->second); // test
8107  }
8108  if((InactiveTrackElementAt(10, HVIt1->second).SpeedTag == SpeedTag) || ((HVIt2 != IMEnd) && (InactiveTrackElementAt(11,
8109  HVIt2->second).SpeedTag == SpeedTag)))
8110  {
8111  Utilities->CallLogPop(557);
8112  return(true);
8113  }
8114  else
8115  {
8116  Utilities->CallLogPop(558);
8117  return(false);
8118  }
8119 }
8120 
8121 // ---------------------------------------------------------------------------
8122 
8123 bool TTrack::ActiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
8124 /*
8125  return true if the SpeedTag present in the map at H & V
8126 */
8127 {
8128  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ActiveMapCheck," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8129  AnsiString(SpeedTag));
8130  if(TrackMap.empty())
8131  {
8132  Utilities->CallLogPop(559);
8133  return(false);
8134  }
8135  THVPair HVPair(HLoc, VLoc);
8136  TTrackMapIterator End = TrackMap.end();
8137  TTrackMapIterator It = End;
8138 
8139  It = TrackMap.find(HVPair);
8140  if((It != End) && (TrackElementAt(19, It->second).SpeedTag == SpeedTag))
8141  {
8142  Utilities->CallLogPop(560);
8143  return(true);
8144  }
8145  else
8146  {
8147  Utilities->CallLogPop(561);
8148  return(false);
8149  }
8150 }
8151 
8152 // ---------------------------------------------------------------------------
8153 
8154 void TTrack::EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
8155 {
8156 /*
8157  General:
8158  All platform, concourse, footcrossing & non-station named location elements are able to have a LocationName allocated, and track
8159  elements (including footcrossings) are able to have an ActiveTrackElementName allocated provided there is an adjacent platform or
8160  a NamedNonStationLocation.
8161  To set these names the user selects a single named location element (not a footcrossing), enters the name, and
8162  this is then allocated as a LocationName to all linked platform, concourse and footcrossing elements, and as an
8163  ActiveTrackElementName to all track elements adjacent to platforms (inc footcrossing tracks if (but only if) they have a
8164  platform at that location).
8165 
8166  Linked named location elements are those explained in TTrack::TTrack()
8167 
8168  Detail:
8169  Two containers are used for allocation of names - LNPendingList, and LNDone2MultiMap, each containing vector positions as
8170  integers and the Map using THVPairs as keys. An adjustment is made for the vector positions as follows:-
8171  inactive vector positions are stored as they are (since most NamedLocationElements are in the inactive vector), but active vector
8172  positions stored as (-1-True Position), so can hold both types in a single integer uniquely - not very elegant but it seems to
8173  work OK! e.g. TrackVector position 0 would be stored as -1, position n would be stored as -1-n. InactiveTrackVector position 0 would be stored as 0.
8174  To recover the true TrackVector position from a stored value the same rule applies, i.e. -1-stored value, equivalent to -1-(-1-original) = -1+1+original = original.
8175 
8176  The List holds elements that have still to be processed, and the Map holds elements that have been processed. On entering
8177  this function a single element should be in the List (normally from the user's selection but can also be from
8178  SearchForAndUpdateLocationName), and the Map is cleared within the function.
8179  A 'while' loop is entered if the List isn't empty, and the front element in it examined. All linked named location elements
8180  (platforms, concourses and footcrossings) that aren't already in either the Map or the List are first added to the List using
8181  AdjElement, then the element itself has it's LocationName set, and any relevant track elements at the same H & V (i.e. adjacent
8182  to a platform) have their ActiveTrackElementName set using AddName. The element is then inserted into the Map and erased from the List.
8183  In this way the list builds up while there are linked elements to be added, but reduces to zero when all are added and processing
8184  moves them into the Map. At the end all linked elements are in the Map.
8185 
8186  Finally any other element that isn't in the Map, i.e. not linked to the current named location, that has the same name as a
8187  LocationName or ActiveTrackElementName, has it erased. This is to allow for deletion of named location elements that split an existing
8188  named location - only one of the sides (selected by whichever the program finds first - the user can't select it) retains the name.
8189 */
8190 
8191 // AnsiString TestString = "H,V,Tag,List Size,DoneMultiMap Size,CurrentElementAddress,MultiMapEntryAddress";//test
8192 // Display->FileDiagnostics(TestString);//test
8193 
8194  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EnterLocationName," + LocationName);
8195  AnsiString TestString1, TestString2; // test
8196 
8197  Track->LNDone2MultiMap.clear();
8198  if(LNPendingList.size() != 1)
8199  {
8200  throw Exception("LNPendingList size not 1 on entry");
8201  }
8202  int CurrentElementNumber; //new after 2.4.3 due to error the JK found (Discord 9/7/20). See note below after 'if(AddingElements)' where CurrentElementNumber is used.
8203  while(!LNPendingList.empty())
8204  {
8205  CurrentElementNumber = LNPendingList.front();
8206  TTrackVectorIterator CurrentElement = GetTrackVectorIteratorFromNamePosition(1, CurrentElementNumber);
8207  int NewElement; // = 2000000000; //marker for unused //not needed from v1.2.0 Beta onwards
8208  int H = CurrentElement->HLoc;
8209  int V = CurrentElement->VLoc;
8210  int Tag = CurrentElement->SpeedTag;
8211  if(Tag == 76) // top plat
8212  {
8213  // AdjElement checks if there is an element matching Tag at H & V that isn't already in LNDone2MultiMap or LNPendingList,
8214  // & returns true if so with the adjusted vector position in NewElement. It checks the appropriate vector
8215  // depending on the SpeedTag value (footcrossings in active vector, rest in inactive vector),
8216  for(int x = 0; x < 25; x++)
8217  {
8218  if(AdjElement(1, H + Tag76Array[x][0], V + Tag76Array[x][1], Tag76Array[x][2], NewElement))
8219  {
8220  LNPendingList.insert(LNPendingList.end(), NewElement);
8221  }
8222  }
8223  }
8224  else if(Tag == 77) // bot plat
8225  {
8226  for(int x = 0; x < 25; x++)
8227  {
8228  if(AdjElement(2, H + Tag77Array[x][0], V + Tag77Array[x][1], Tag77Array[x][2], NewElement))
8229  {
8230  LNPendingList.insert(LNPendingList.end(), NewElement);
8231  }
8232  }
8233  }
8234  else if(Tag == 78) // l plat
8235  {
8236  for(int x = 0; x < 25; x++)
8237  {
8238  if(AdjElement(3, H + Tag78Array[x][0], V + Tag78Array[x][1], Tag78Array[x][2], NewElement))
8239  {
8240  LNPendingList.insert(LNPendingList.end(), NewElement);
8241  }
8242  }
8243  }
8244  else if(Tag == 79) // r plat
8245  {
8246  for(int x = 0; x < 25; x++)
8247  {
8248  if(AdjElement(4, H + Tag79Array[x][0], V + Tag79Array[x][1], Tag79Array[x][2], NewElement))
8249  {
8250  LNPendingList.insert(LNPendingList.end(), NewElement);
8251  }
8252  }
8253  }
8254  else if(Tag == 96) // conc
8255  {
8256  for(int x = 0; x < 28; x++)
8257  {
8258  if(AdjElement(5, H + Tag96Array[x][0], V + Tag96Array[x][1], Tag96Array[x][2], NewElement))
8259  {
8260  LNPendingList.insert(LNPendingList.end(), NewElement);
8261  }
8262  }
8263  }
8264  else if(Tag == 129) // vert footbridge
8265  {
8266  for(int x = 0; x < 8; x++)
8267  {
8268  if(AdjElement(6, H + Tag129Array[x][0], V + Tag129Array[x][1], Tag129Array[x][2], NewElement))
8269  {
8270  LNPendingList.insert(LNPendingList.end(), NewElement);
8271  }
8272  }
8273  }
8274  else if(Tag == 130) // hor footbridge
8275  {
8276  for(int x = 0; x < 8; x++)
8277  {
8278  if(AdjElement(7, H + Tag130Array[x][0], V + Tag130Array[x][1], Tag130Array[x][2], NewElement))
8279  {
8280  LNPendingList.insert(LNPendingList.end(), NewElement);
8281  }
8282  }
8283  }
8284  else if(Tag == 131) // named location
8285  {
8286  for(int x = 0; x < 4; x++)
8287  {
8288  if(AdjElement(8, H + Tag131Array[x][0], V + Tag131Array[x][1], Tag131Array[x][2], NewElement))
8289  {
8290  LNPendingList.insert(LNPendingList.end(), NewElement);
8291  }
8292  }
8293  }
8294  else if(Tag == 145) // v u'pass
8295  {
8296  for(int x = 0; x < 8; x++)
8297  {
8298  if(AdjElement(9, H + Tag145Array[x][0], V + Tag145Array[x][1], Tag145Array[x][2], NewElement))
8299  {
8300  LNPendingList.insert(LNPendingList.end(), NewElement);
8301  }
8302  }
8303  }
8304  else if(Tag == 146) // h u'pass
8305  {
8306  for(int x = 0; x < 8; x++)
8307  {
8308  if(AdjElement(10, H + Tag146Array[x][0], V + Tag146Array[x][1], Tag146Array[x][2], NewElement))
8309  {
8310  LNPendingList.insert(LNPendingList.end(), NewElement);
8311  }
8312  }
8313  }
8314  // below new at v1.1.0 but condition changed at v1.1.4 as interfered with name changes for single element locations
8315 // if(NewElement != 2000000000) //adjacent element found & new element inserted, check if a (different) name already allocated and if so erase it from text vector
8316  if(AddingElements)
8317  {
8318  int HPos, VPos; // not used but needed for FindText function
8319  if(CurrentElementNumber > -1) //up to & including 2.4.2 this was NewElement, which was the last one added during LNPendingList building above, so it could be
8320  //repeatedly selected rather than the element under examination (LNPendingList.front()) & the front element text name wouldn't be erased.
8321  //Using CurrentElementNumber ensures that all elements are examined & have names erased if present
8322  {
8323  AnsiString ExistingName = InactiveTrackElementAt(118, CurrentElementNumber).LocationName; //existing name of CurrentElement
8324  if((ExistingName != "") && (ExistingName != LocationName))
8325  {
8326  if(LocationNameMultiMap.find(ExistingName) == Track->LocationNameMultiMap.end())
8327  {
8328  } // name not in LocationNameMultiMap, so don't erase from TextVector
8329  else if(TextHandler->FindText(4, ExistingName, HPos, VPos)) // can't use 'EraseLocationNameText' as that function is in TInterface
8330  {
8331  if(TextHandler->TextErase(10, HPos, VPos, ExistingName))
8332  {
8333  ;
8334  } // condition not used
8335 
8336  }
8337  }
8338  }
8339  }
8340  AddName(1, CurrentElement, LocationName); // add location name to current element, + timetable name to any
8341  // track at that loc
8342  THVPair HVPair(H, V);
8343  TLNDone2MultiMapEntry LNDone2MultiMapEntry;
8344  LNDone2MultiMapEntry.first = HVPair;
8345  LNDone2MultiMapEntry.second = LNPendingList.front();
8346  LNDone2MultiMap.insert(LNDone2MultiMapEntry);
8347  LNPendingList.erase(LNPendingList.begin());
8348  }
8349 
8350 // search all name multimap for same name where corresponding active elements don't appear in
8351 // LNDone2MultiMap & erase the name for all elements at that H & V in both active & inactive vectors
8352 
8353  TLocationNameMultiMapIterator SNIterator;
8354  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
8355  bool FoundFlag, ErasedFlag = false;
8356 
8357  if(SNRange.first != SNRange.second)
8358  {
8359  SNRange.first--; // now pointing to before the first
8360  SNRange.second--; // now pointing to the last
8361  for(SNIterator = SNRange.second; SNIterator != SNRange.first; SNIterator--)
8362  {
8363  // Same elements are in Done map as in name map
8364  if(!ElementInLNDone2MultiMap(1, SNIterator->second))
8365  {
8366  ErasedFlag = true;
8367  TTrackVectorIterator TVIt = GetTrackVectorIteratorFromNamePosition(2, SNIterator->second);
8368  TVIt->LocationName = "";
8369  TVIt->ActiveTrackElementName = ""; // in case it's a footcrossing
8370  // need to erase the timetable name in a track element at same H&V if present (i.e. if a platform)
8371  if((TVIt->TrackType == Platform) || (TVIt->TrackType == NamedNonStationLocation))
8372  {
8373  int Position = GetVectorPositionFromTrackMap(17, TVIt->HLoc, TVIt->VLoc, FoundFlag);
8374  if(FoundFlag)
8375  {
8376  TrackElementAt(20, Position).LocationName = "";
8377  TrackElementAt(21, Position).ActiveTrackElementName = "";
8378  }
8379  }
8380  // erase name in name map
8381 // ChangeLocationNameMultiMapEntry("", SNIterator); can't use this as interferes with the iterators
8382  }
8383  }
8384  }
8385  if(ErasedFlag)
8386  {
8388  }
8389  if(TrackFinished)
8390  {
8392  }
8393 // set here as well as in LinkTrack so don't have to link track just because a name added
8394 // if track not finished then will be set when track validated
8395 
8396 // Rebuild ContinuationNameMap - added at v2.6.1 due to error found by Andrekoener & notified by discord on 16/12/20
8397 // error was that if a continuation name was changed and a timetable stopping place included that new name then ContinuationNameMap wouldn't be rebuilt
8398 // so the timetable would validate and load and the name would appear in the dropdown list. The reason was that ContinuationNameMap was only built in TryToLinkTrack,
8399 // so if that isn't called (as it isn't for a name change) then the error wouldn't be seen. However next time the railway was loaded TryToLinkTrack was called
8400 // so the error would be seen.
8401 // This inclusion rebuilds ContinuationNameMap whenever a name is entered or changed so the error can no longer be hidden.
8402  std::pair<AnsiString, char>TempMapPair;
8403 
8404  ContinuationNameMap.clear();
8405  for(int x = 0; x < Track->TrackVectorSize(); x++)
8406  {
8407  if((Track->TrackElementAt(1356, x).TrackType == Continuation) && (Track->TrackElementAt(1357, x).ActiveTrackElementName != ""))
8408  {
8409  TempMapPair.first = Track->TrackElementAt(1358, x).ActiveTrackElementName;
8410  TempMapPair.second = 'x'; // unused
8411  ContinuationNameMap.insert(TempMapPair);
8412  }
8413  }
8414 //end of addition
8415  CheckLocationNameMultiMap(1); // test
8416  Utilities->CallLogPop(562);
8417 }
8418 
8419 // ---------------------------------------------------------------------------
8420 
8421 bool TTrack::AdjElement(int Caller, int HLoc, int VLoc, int SpeedTag, int &FoundElement)
8422 /*
8423  Looks for a FixedNamedLocationElement at H & V with SpeedTag, and if found and not already present in either the
8424  LNDone2MultiMap or the LNPendingList returns an int corresponding to the adjusted vector position.
8425 */
8426 {
8427  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AdjElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8428  AnsiString(SpeedTag));
8429  if(!NamedLocationElementAt(2, HLoc, VLoc))
8430  {
8431  Utilities->CallLogPop(948);
8432  return(false);
8433  }
8434  bool FoundFlag;
8435  int Position = -1;
8436  TIMPair IMPair;
8437 
8438  if((SpeedTag == 129) || (SpeedTag == 130) || (SpeedTag == 145) || (SpeedTag == 146)) // footcrossing - only in active vector
8439  {
8440  Position = GetVectorPositionFromTrackMap(18, HLoc, VLoc, FoundFlag);
8441  if(FoundFlag)
8442  {
8443  if(TrackElementAt(22, Position).SpeedTag == SpeedTag)
8444  {
8445  int MapPos = -1 - Position; // MapPos is the adjusted entry in the list & map
8446  if(!ElementInLNDone2MultiMap(2, MapPos) && !ElementInLNPendingList(1, MapPos))
8447  // don't allow duplicates in either list, or processing takes a lot longer
8448  {
8449  FoundElement = MapPos;
8450  Utilities->CallLogPop(563);
8451  return(true);
8452  }
8453  }
8454  }
8455  }
8456  else
8457  {
8458  IMPair = GetVectorPositionsFromInactiveTrackMap(8, HLoc, VLoc, FoundFlag);
8459  if(FoundFlag)
8460  {
8461  if(InactiveTrackElementAt(12, IMPair.first).SpeedTag == SpeedTag)
8462  {
8463  if(!ElementInLNDone2MultiMap(3, IMPair.first) && !ElementInLNPendingList(2, IMPair.first))
8464  {
8465  FoundElement = IMPair.first;
8466  Utilities->CallLogPop(564);
8467  return(true);
8468  }
8469  }
8470  else if(InactiveTrackElementAt(13, IMPair.second).SpeedTag == SpeedTag)
8471  {
8472  if(!ElementInLNDone2MultiMap(4, IMPair.second) && !ElementInLNPendingList(3, IMPair.second))
8473  {
8474  FoundElement = IMPair.second;
8475  Utilities->CallLogPop(565);
8476  return(true);
8477  }
8478  }
8479  }
8480  }
8481  Utilities->CallLogPop(566);
8482  return(false);
8483 }
8484 
8485 // ---------------------------------------------------------------------------
8486 
8487 void TTrack::AddName(int Caller, TTrackVectorIterator TrackElement, AnsiString Name)
8488 /*
8489  Add location name to TrackElement and ActiveTrackElementName to any elements in trackmap
8490  at same H & V if TrackElement is a Platform or named non-station location. Also update LocationNameMultiMap
8491  with the new name
8492 */
8493 {
8494  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddName," + TrackElement->LogTrack(6) + "," + Name);
8495  AnsiString OldName = TrackElement->LocationName, ErrorString; // declare new AnsiStrings OldName (set to existing name) & ErrorString
8496 
8497  TrackElement->LocationName = Name; // covers all FixedNamedLocationElement whichever vector they are in
8498  int HLoc = TrackElement->HLoc;
8499  int VLoc = TrackElement->VLoc;
8500  bool FoundFlag;
8501 
8502  if((TrackElement->TrackType == Platform) || (TrackElement->TrackType == NamedNonStationLocation))
8503  // only have timetable names for adjacent platforms & named locations
8504  {
8505  int Position = GetVectorPositionFromTrackMap(19, HLoc, VLoc, FoundFlag);
8506  if(FoundFlag)
8507  {
8508  TrackElementAt(23, Position).ActiveTrackElementName = Name;
8509  }
8510  }
8511  TLocationNameMultiMapIterator SNIterator = FindNamedElementInLocationNameMultiMap(4, OldName, TrackElement, ErrorString);
8512 
8513  if(ErrorString != "")
8514  {
8515  throw Exception(ErrorString + " in AddName for OldName == " + OldName);
8516  }
8517  ChangeLocationNameMultiMapEntry(1, Name, SNIterator); // OK, can use it here as not in an iterator loop
8518  CheckLocationNameMultiMap(2); // test
8519  Utilities->CallLogPop(567);
8520 }
8521 
8522 // ---------------------------------------------------------------------------
8523 
8524 bool TTrack::ElementInLNDone2MultiMap(int Caller, int MapPos)
8525 /*
8526  Examines LNDone2MultiMap to see whether the MapPos value is present, and returns true if so.
8527 */
8528 {
8529  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ElementInLNDone2MultiMap," + AnsiString(MapPos));
8530  if(LNDone2MultiMap.empty())
8531  {
8532  Utilities->CallLogPop(568);
8533  return(false);
8534  }
8535  TLNDone2MultiMapIterator LNDone2MultiMapIterator;
8536 
8537  for(LNDone2MultiMapIterator = LNDone2MultiMap.begin(); LNDone2MultiMapIterator != LNDone2MultiMap.end(); LNDone2MultiMapIterator++)
8538  {
8539  if(LNDone2MultiMapIterator->second == MapPos)
8540  {
8541  Utilities->CallLogPop(569);
8542  return(true);
8543  }
8544  }
8545  Utilities->CallLogPop(570);
8546  return(false);
8547 }
8548 
8549 // ---------------------------------------------------------------------------
8550 
8551 bool TTrack::ElementInLNPendingList(int Caller, int MapPos)
8552 /*
8553  Examines LNPendingList to see whether the MapPos value is present, and returns true if so.
8554 */
8555 {
8556  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ElementInLNPendingList," + AnsiString(MapPos));
8557  if(LNPendingList.empty())
8558  {
8559  Utilities->CallLogPop(571);
8560  return(false);
8561  }
8562  TLNPendingListIterator LNPendingListIterator;
8563 
8564  for(LNPendingListIterator = LNPendingList.begin(); LNPendingListIterator != LNPendingList.end(); LNPendingListIterator++)
8565  {
8566  if(*LNPendingListIterator == MapPos)
8567  {
8568  Utilities->CallLogPop(572);
8569  return(true);
8570  }
8571  }
8572  Utilities->CallLogPop(573);
8573  return(false);
8574 }
8575 
8576 // ---------------------------------------------------------------------------
8577 
8578 bool TTrack::NamedLocationElementAt(int Caller, int HLoc, int VLoc)
8579 /*
8580  Examines element at H & V, and returns true if its FixedNamedLocationElement bool is true
8581 */
8582 {
8583  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NamedLocationElementAt," + AnsiString(HLoc) + "," + AnsiString(VLoc));
8584  THVPair HVPair(HLoc, VLoc);
8585  TTrackMapIterator TrackMapPtr = TrackMap.find(HVPair);
8586  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(HVPair);
8587 
8588  if(TrackMapPtr != TrackMap.end()) // =end() if not found
8589  {
8590  if(TrackElementAt(24, TrackMapPtr->second).FixedNamedLocationElement)
8591  {
8592  Utilities->CallLogPop(574);
8593  return(true);
8594  }
8595  }
8596  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
8597  // may be 2 platforms at location but if so both FixedNamedLocationElement bools will be set, so only need to find one
8598  {
8599  if(InactiveTrackElementAt(14, InactiveTrack2MultiMapIterator->second).FixedNamedLocationElement)
8600  {
8601  Utilities->CallLogPop(575);
8602  return(true);
8603  }
8604  }
8605  Utilities->CallLogPop(576);
8606  return(false);
8607 }
8608 
8609 // ---------------------------------------------------------------------------
8610 
8611 bool TTrack::LocationNameAllocated(int Caller, AnsiString LocationName) // true if a non-empty LocationName found in LocationNameMultiMap
8612 {
8613  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LocationNameAllocated," + LocationName);
8614  if(Track->LocationNameMultiMap.find(LocationName) != Track->LocationNameMultiMap.end())
8615  {
8616  Utilities->CallLogPop(1953);
8617  return(true);
8618  }
8619  Utilities->CallLogPop(1954);
8620  return(false);
8621 }
8622 
8623 // ---------------------------------------------------------------------------
8624 
8625 bool TTrack::DuplicatedLocationName(int Caller, bool GiveMessage)
8626 //examines LocationNameMultiMap and returns true if there are two or more locations with the same name - added at v2.6.1 to cater for Bill78's new .dev file merge
8627 //program and used when try to save as a .rly file
8628 {
8629  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DuplicatedLocationName");
8632  if(LocationNameMultiMap.empty()) //no names so no duplicates
8633  {
8634  Utilities->CallLogPop(2254);
8635  return(false);
8636  }
8637  AnsiString NameBeingChecked = LocationNameMultiMap.begin()->first; //first name to start with
8638  LNMMRg = LocationNameMultiMap.equal_range(NameBeingChecked);
8639  if(NameBeingChecked != "") //added for v2.6.2 as 2.6.1 reported duplicate null names (reported by Micke(Commuterpop) 06/01/21 via discord)
8640  {
8642  {
8643  if(GiveMessage)
8644  {
8645  ShowMessage("Please note that more than one instance of " + NameBeingChecked + " was found. Location names must be unique before the railway can be saved as a .rly file");
8646  }
8647  Utilities->CallLogPop(2255);
8648  return(true);
8649  }
8650  }
8651  while(LNMMRg.second != LocationNameMultiMap.end()) //here LNMMRg still set to earlier name
8652  {
8653  NameBeingChecked = LNMMRg.second->first; //this is the next name as LNMMRg->second points to the first location NOT containing the first name
8654  LNMMRg = LocationNameMultiMap.equal_range(NameBeingChecked); //here LNMMRg is the new range
8655  if(NameBeingChecked != "") //should have skipped all null names as all listed together but add to be on the safe side
8656  {
8658  {
8659  if(GiveMessage)
8660  {
8661  ShowMessage("Please note that more than one instance of " + NameBeingChecked + " was found. Location names must be unique before the railway can be saved as a .rly file");
8662  }
8663  Utilities->CallLogPop(2256);
8664  return(true);
8665  }
8666  }
8667  }
8668  Utilities->CallLogPop(2257);
8669  return(false); //OK, no duplicates
8670 }
8671 
8672 // ---------------------------------------------------------------------------
8673 
8675 {
8676  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PopulateHVPairsLinkedMapAndNoDuplicates");
8677  THVPair HVPair;
8678  THVPairsLinkedMap HVPairsLinkedMap; //this is a map of HVPairs (so each is unique), each with a boolean marker, false for not linked and true for linked
8679  //for use in the duplicate check
8680  for(TLocationNameMultiMapIterator LNMMIt = LNMMRg.first; LNMMIt != LNMMRg.second; LNMMIt++) //populating the linked map
8681  {
8682  if(LNMMIt->second < 0) //active track element
8683  {
8684  HVPair.first = TrackElementAt(1011, (-1 - LNMMIt->second)).HLoc;
8685  HVPair.second = TrackElementAt(1012, (-1 - LNMMIt->second)).VLoc;
8686  }
8687  else //inactive track element
8688  {
8689  HVPair.first = InactiveTrackElementAt(134, LNMMIt->second).HLoc;
8690  HVPair.second = InactiveTrackElementAt(135, LNMMIt->second).VLoc;
8691  }
8692  HVPairsLinkedMap.insert(std::pair<THVPair, bool>(HVPair, false)); //set all bools to false initially
8693  }
8694  //All HVPairs now present in HVPairsLinkedMap for the specific location name
8695 
8696  //now need to identify all named elements that are linked either vertically or horizontally with the first one (could be any but must be just one)
8697  //so that at the end any that haven't been identified aren't linked and so represent a duplicated name
8698  //to do so need a list (works like LNPendingList) to hold all elements that haven't been checked for links
8699 
8700  std::list<THVPair> HVLinkedList;
8701 
8702  //set the first value to true and add it to the list
8703  HVPairsLinkedMap.begin()->second = true;
8704  HVLinkedList.push_back(HVPairsLinkedMap.begin()->first);
8705  //now enter a loop to examine the front pair in the list and set all linked bools to true, and if they weren't already true then add them to the back of the list for later
8706  //examination
8707  THVPair HVPairUnderExamination;
8708  THVPairsLinkedMap::iterator HVPLMIt;
8709  THVPair HVPairNew;
8710  while(!HVLinkedList.empty())
8711  {
8712  HVPairUnderExamination = HVLinkedList.front();
8713  HVLinkedList.pop_front();
8714  HVPairNew.first = HVPairUnderExamination.first;
8715  HVPairNew.second = HVPairUnderExamination.second - 1; //position directly above element
8716  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8717  if(HVPLMIt != HVPairsLinkedMap.end())
8718  {
8719  if(!HVPLMIt->second)
8720  {
8721  HVLinkedList.push_back(HVPLMIt->first);
8722  }
8723  HVPLMIt->second = true;
8724  }
8725  HVPairNew.first = HVPairUnderExamination.first - 1;
8726  HVPairNew.second = HVPairUnderExamination.second; //position to the left of the element
8727  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8728  if(HVPLMIt != HVPairsLinkedMap.end())
8729  {
8730  if(!HVPLMIt->second)
8731  {
8732  HVLinkedList.push_back(HVPLMIt->first);
8733  }
8734  HVPLMIt->second = true;
8735  }
8736  HVPairNew.first = HVPairUnderExamination.first;
8737  HVPairNew.second = HVPairUnderExamination.second + 1; //position under the element
8738  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8739  if(HVPLMIt != HVPairsLinkedMap.end())
8740  {
8741  if(!HVPLMIt->second)
8742  {
8743  HVLinkedList.push_back(HVPLMIt->first);
8744  }
8745  HVPLMIt->second = true;
8746  }
8747  HVPairNew.first = HVPairUnderExamination.first + 1;
8748  HVPairNew.second = HVPairUnderExamination.second; //position to the right of the element
8749  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8750  if(HVPLMIt != HVPairsLinkedMap.end())
8751  {
8752  if(!HVPLMIt->second)
8753  {
8754  HVLinkedList.push_back(HVPLMIt->first);
8755  }
8756  HVPLMIt->second = true;
8757  }
8758  }
8759 
8760  //at the end if any have a false bool then the name is duplicated so return false
8761  for(THVPairsLinkedMap::iterator HVPLMIt = HVPairsLinkedMap.begin(); HVPLMIt != HVPairsLinkedMap.end(); HVPLMIt++)
8762  {
8763  if(!HVPLMIt->second)
8764  {
8765  Utilities->CallLogPop(2258);
8766  return(false);
8767  }
8768  }
8769  Utilities->CallLogPop(2259);
8770  return(true);
8771 }
8772 
8773 // ---------------------------------------------------------------------------
8774 
8775 bool TTrack::TimetabledLocationNameAllocated(int Caller, AnsiString LocationName)
8776 /*
8777  Examines ActiveTrackElementNameMap and returns true if the LocationName is found and isn't "" (used to use LocationNameMultiMap)
8778 */
8779 
8780 {
8781  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TimetabledLocationNameAllocated," + LocationName);
8782  if(LocationName == "")
8783  {
8784  Utilities->CallLogPop(577);
8785  return(false);
8786  }
8787 // new for v0.2b
8788 // compile ActiveTrackElementNameMap if !ActiveTrackElementNameMapCompiledFlag (added as a precaution, should be compiled when reach here)
8790  {
8791  TActiveTrackElementNameMapEntry ActiveTrackElementNameMapEntry;
8792  ActiveTrackElementNameMap.clear();
8793  for(unsigned int x = 0; x < TrackVector.size(); x++)
8794  {
8795  if((TrackElementAt(1359, x).ActiveTrackElementName != "") && (ContinuationNameMap.find(TrackElementAt(1360, x).ActiveTrackElementName))
8796  == ContinuationNameMap.end())
8797  {
8798  // exclude any name that appears in a continuation, error message given in tt validation if try to include such a name in a tt
8799  ActiveTrackElementNameMapEntry.first = Track->TrackElementAt(1361, x).ActiveTrackElementName;
8800  ActiveTrackElementNameMapEntry.second = 0; // this is a dummy value
8801  ActiveTrackElementNameMap.insert(ActiveTrackElementNameMapEntry);
8802  }
8803  }
8805  }
8806  Utilities->CallLogPop(578);
8807  return (ActiveTrackElementNameMap.find(LocationName) != ActiveTrackElementNameMap.end());
8808 // end of new section
8809 // return (LocationNameMultiMap.find(LocationName) != LocationNameMultiMap.end());
8810 }
8811 
8812 // ---------------------------------------------------------------------------
8813 
8814 void TTrack::EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
8815 /*
8816  Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both active and inactive vectors) have the
8817  name erased both as a LocationName and a ActiveTrackElementName. The LocationNameMultiMap is also rebuilt to correspond to the
8818  new names in the vectors.
8819 */
8820 {
8821  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseLocationAndActiveTrackElementNames," + LocationName);
8822  bool FoundFlag, ErasedFlag = false;
8823  TLocationNameMultiMapIterator SNIterator;
8824  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
8825 
8826  if(SNRange.first != SNRange.second)
8827  {
8828  ErasedFlag = true;
8829  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
8830  {
8831  TTrackVectorIterator TVIt = GetTrackVectorIteratorFromNamePosition(3, SNIterator->second);
8832  TVIt->LocationName = "";
8833  TVIt->ActiveTrackElementName = ""; // in case it's a footcrossing
8834  // need to erase the timetable name in a track element at same H&V if present (i.e. if a platform or namedlocation)
8835  if((TVIt->TrackType == Platform) || (TVIt->TrackType == NamedNonStationLocation))
8836  {
8837  int Position = GetVectorPositionFromTrackMap(20, TVIt->HLoc, TVIt->VLoc, FoundFlag);
8838  if(FoundFlag)
8839  {
8840  TrackElementAt(25, Position).LocationName = "";
8841  TrackElementAt(26, Position).ActiveTrackElementName = "";
8842  }
8843  }
8844  }
8845  }
8846  if(ErasedFlag)
8847  {
8849  }
8850  CheckLocationNameMultiMap(3); // test
8851  Utilities->CallLogPop(579);
8852 }
8853 
8854 // ---------------------------------------------------------------------------
8855 
8856 void TTrack::SearchForAndUpdateLocationName(int Caller, int HLoc, int VLoc, int SpeedTag)
8857 /*
8858  NB No longer used during EraseTrackElement, too long-winded - erase all name now if any part removed, user needs to re-enter
8859  Checks all locations that are adjacent to the one entered for linked named location elements, and if any LocationName is found
8860  in any of the linked elements that name is used for all elements that are now linked to it. The location entered doesn't
8861  need to be a FixedNamedLocationElement and there doesn't even need to be an element there. Used during EraseTrackElement (in which
8862  case the SpeedTag is that for the element that is erased) and PlotAndAddTrackElement, to bring the named location and timetable
8863  naming up to date with the deletion or insertion.
8864 */
8865 {
8866  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForAndUpdateLocationName," + AnsiString(HLoc) + "," +
8867  AnsiString(VLoc) + "," + AnsiString(SpeedTag));
8868  LNPendingList.clear();
8869  AnsiString LocationName;
8870  int MapPos;
8871  bool FoundFlag = 0;
8872 
8873 //first check if this element is inactive and named, and if so use its position and name (new at v2.6.0 to allow pasted named locations to name linked elements)
8874  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(30, HLoc, VLoc, FoundFlag);
8875  if(FoundFlag)
8876  {
8877  LocationName = InactiveTrackElementAt(132, IMPair.first).LocationName;
8878  if(LocationName != "")
8879  {
8880  LNPendingList.insert(Track->LNPendingList.end(), IMPair.first);
8881  EnterLocationName(13, LocationName, true);
8882  Utilities->CallLogPop(2251);
8883  return;
8884  }
8885  LocationName = InactiveTrackElementAt(133, IMPair.second).LocationName;
8886  if(LocationName != "")
8887  {
8888  LNPendingList.insert(Track->LNPendingList.end(), IMPair.second);
8889  EnterLocationName(14, LocationName, true);
8890  Utilities->CallLogPop(2252);
8891  return;
8892  }
8893  }
8894 //then check if this element is active and named, and if so use its position (-Pos-1) and name (new at v2.6.0 to allow pasted named locations to name linked elements)
8895 
8896  int Position = GetVectorPositionFromTrackMap(59, HLoc, VLoc, FoundFlag);
8897  if(FoundFlag)
8898  {
8899  LocationName = TrackElementAt(1004, Position).LocationName;
8900  if(LocationName != "")
8901  {
8902  int ModifiedPosition = -1 - Position;
8903  LNPendingList.insert(Track->LNPendingList.end(), ModifiedPosition);
8904  EnterLocationName(15, LocationName, true);
8905  Utilities->CallLogPop(2253);
8906  return;
8907  }
8908  }
8909  if(SpeedTag == 76) // top plat
8910  {
8911  for(int x = 0; x < 25; x++)
8912  {
8913  if(AdjNamedElement(1, HLoc + Tag76Array[x][0], VLoc + Tag76Array[x][1], Tag76Array[x][2], LocationName, MapPos))
8914  {
8915  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8916  EnterLocationName(3, LocationName, true);
8917  break;
8918  }
8919  }
8920  }
8921  else if(SpeedTag == 77) // bot plat
8922  {
8923  for(int x = 0; x < 25; x++)
8924  {
8925  if(AdjNamedElement(2, HLoc + Tag77Array[x][0], VLoc + Tag77Array[x][1], Tag77Array[x][2], LocationName, MapPos))
8926  {
8927  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8928  EnterLocationName(4, LocationName, true);
8929  break;
8930  }
8931  }
8932  }
8933  else if(SpeedTag == 78) // l plat
8934  {
8935  for(int x = 0; x < 25; x++)
8936  {
8937  if(AdjNamedElement(3, HLoc + Tag78Array[x][0], VLoc + Tag78Array[x][1], Tag78Array[x][2], LocationName, MapPos))
8938  {
8939  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8940  EnterLocationName(5, LocationName, true);
8941  break;
8942  }
8943  }
8944  }
8945  else if(SpeedTag == 79) // r plat
8946  {
8947  for(int x = 0; x < 25; x++)
8948  {
8949  if(AdjNamedElement(4, HLoc + Tag79Array[x][0], VLoc + Tag79Array[x][1], Tag79Array[x][2], LocationName, MapPos))
8950  {
8951  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8952  EnterLocationName(6, LocationName, true);
8953  break;
8954  }
8955  }
8956  }
8957  else if(SpeedTag == 96) // conc
8958  {
8959  for(int x = 0; x < 28; x++)
8960  {
8961  if(AdjNamedElement(5, HLoc + Tag96Array[x][0], VLoc + Tag96Array[x][1], Tag96Array[x][2], LocationName, MapPos))
8962  {
8963  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8964  EnterLocationName(7, LocationName, true);
8965  break;
8966  }
8967  }
8968  }
8969  else if(SpeedTag == 129) // vert footbridge
8970  {
8971  for(int x = 0; x < 8; x++)
8972  {
8973  if(AdjNamedElement(6, HLoc + Tag129Array[x][0], VLoc + Tag129Array[x][1], Tag129Array[x][2], LocationName, MapPos))
8974  {
8975  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8976  EnterLocationName(8, LocationName, true);
8977  break;
8978  }
8979  }
8980  }
8981  else if(SpeedTag == 130) // hor footbridge
8982  {
8983  for(int x = 0; x < 8; x++)
8984  {
8985  if(AdjNamedElement(7, HLoc + Tag130Array[x][0], VLoc + Tag130Array[x][1], Tag130Array[x][2], LocationName, MapPos))
8986  {
8987  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8988  EnterLocationName(9, LocationName, true);
8989  break;
8990  }
8991  }
8992  }
8993  else if(SpeedTag == 145) // vert u'pass
8994  {
8995  for(int x = 0; x < 8; x++)
8996  {
8997  if(AdjNamedElement(9, HLoc + Tag145Array[x][0], VLoc + Tag145Array[x][1], Tag145Array[x][2], LocationName, MapPos))
8998  {
8999  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9000  EnterLocationName(11, LocationName, true);
9001  break;
9002  }
9003  }
9004  }
9005  else if(SpeedTag == 146) // hor u'pass
9006  {
9007  for(int x = 0; x < 8; x++)
9008  {
9009  if(AdjNamedElement(10, HLoc + Tag146Array[x][0], VLoc + Tag146Array[x][1], Tag146Array[x][2], LocationName, MapPos))
9010  {
9011  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9012  EnterLocationName(12, LocationName, true);
9013  break;
9014  }
9015  }
9016  }
9017  else if(SpeedTag == 131) // named location
9018  {
9019  for(int x = 0; x < 4; x++)
9020  {
9021  if(AdjNamedElement(8, HLoc + Tag131Array[x][0], VLoc + Tag131Array[x][1], Tag131Array[x][2], LocationName, MapPos))
9022  {
9023  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9024  EnterLocationName(10, LocationName, true);
9025  break;
9026  }
9027  }
9028  }
9029 // AddName(HLoc, VLoc, LocationName);//don't need this now, EnterLocationName takes care of it
9030  Utilities->CallLogPop(580);
9031 }
9032 
9033 // ---------------------------------------------------------------------------
9034 
9035 bool TTrack::AdjNamedElement(int Caller, int HLoc, int VLoc, int SpeedTag, AnsiString &LocationName, int &FoundElement)
9036 /*
9037  Used in SearchForAndUpdateLocationName to check for elements in TrackMap & InactiveTrackMap that match H, V & Tag, & returns
9038  true if a LocationName is found, and also returns the name and the adjusted vector position.
9039 */
9040 {
9041  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AdjNamedElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
9042  AnsiString(SpeedTag));
9043  bool FoundFlag;
9044  TIMPair IMPair;
9045  TTrackVectorIterator TempElement;
9046  int Position;
9047 
9048  IMPair = GetVectorPositionsFromInactiveTrackMap(9, HLoc, VLoc, FoundFlag);
9049  if(FoundFlag)
9050  {
9051  if(InactiveTrackElementAt(15, IMPair.first).SpeedTag == SpeedTag)
9052  {
9053  TempElement = InactiveTrackVector.begin() + IMPair.first;
9054  if(TempElement->LocationName != "")
9055  {
9056  LocationName = TempElement->LocationName;
9057  FoundElement = IMPair.first;
9058  Utilities->CallLogPop(581);
9059  return(true);
9060  }
9061  }
9062  else if(InactiveTrackElementAt(16, IMPair.second).SpeedTag == SpeedTag)
9063  {
9064  TempElement = InactiveTrackVector.begin() + IMPair.second;
9065  if(TempElement->LocationName != "")
9066  {
9067  LocationName = TempElement->LocationName;
9068  FoundElement = IMPair.second;
9069  Utilities->CallLogPop(582);
9070  return(true);
9071  }
9072  }
9073  }
9074  Position = GetVectorPositionFromTrackMap(21, HLoc, VLoc, FoundFlag);
9075  if(FoundFlag)
9076  {
9077  if(TrackElementAt(27, Position).SpeedTag == SpeedTag)
9078  {
9079  TempElement = TrackVector.begin() + Position;
9080  if(TempElement->LocationName != "")
9081  {
9082  LocationName = TempElement->LocationName;
9083  FoundElement = -1 - Position;
9084  Utilities->CallLogPop(583);
9085  return(true);
9086  }
9087  }
9088  }
9089  Utilities->CallLogPop(584);
9090  return(false);
9091 }
9092 
9093 // ---------------------------------------------------------------------------
9094 
9095 void TTrack::CheckLocationNameMultiMap(int Caller) // test function
9096 {
9097 // check quantity in map & vectors match
9098  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckLocationNameMultiMap,");
9099  unsigned int Count = 0;
9100 
9101  if(SkipLocationNameMultiMapCheck) // renamed in v2.4.0 to skip check when pasting because fails as map elements not fully aligned until all pasted
9102  {
9103  Utilities->CallLogPop(2059);
9104  return;
9105  }
9106  AnsiString SName, TName, ErrorString;
9107 
9108  for(unsigned int x = 0; x < TrackVector.size(); x++)
9109  {
9110  if(TrackElementAt(1362, x).FixedNamedLocationElement)
9111  {
9112  if(TrackElementAt(1363, x).TrackType != FootCrossing)
9113  {
9114  throw Exception("Track element has FixedNamedLocationElement set but is not a footbridge/underpass in CheckLocationNameMultiMap, caller = " +
9115  AnsiString(Caller));
9116  }
9117  Count++;
9118  }
9119  }
9120  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
9121  {
9122  if(InactiveTrackElementAt(143, x).FixedNamedLocationElement)
9123  {
9124  if((InactiveTrackElementAt(144, x).TrackType != Platform) && (InactiveTrackElementAt(145, x).TrackType != NamedNonStationLocation) &&
9125  (InactiveTrackElementAt(146, x).TrackType != Concourse))
9126  {
9127  throw Exception
9128  ("Inactive track element has FixedNamedLocationElement set but is not a platform, concourse or named location in CheckLocationNameMultiMap, caller = " +
9129  AnsiString(Caller));
9130  }
9131  Count++;
9132  }
9133  }
9134  if(LocationNameMultiMap.size() != Count)
9135  {
9136  throw Exception("LocationNameMultiMap size = " + AnsiString(LocationNameMultiMap.size()) + " & Count = " + AnsiString(Count) +
9137  " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
9138  }
9139 // check all entries in both vectors match entries in name multimap
9141 
9142  for(unsigned int x = 0; x < TrackVector.size(); x++)
9143  {
9144  if(TrackElementAt(1364, x).FixedNamedLocationElement)
9145  {
9146  SName = TrackElementAt(1365, x).LocationName;
9147  SNIt = FindNamedElementInLocationNameMultiMap(5, SName, TrackVector.begin() + x, ErrorString);
9148  if(ErrorString != "")
9149  {
9150  throw Exception(ErrorString + " in CheckLocationNameMultiMap for TrackVector check, caller = " + AnsiString(Caller));
9151  }
9152  if(SNIt->second != -1 - (int)x)
9153  {
9154  throw Exception("Elements different in name map & TrackVector in CheckLocationNameMultiMap for TrackVector check, caller = " +
9155  AnsiString(Caller));
9156  }
9157  }
9158  // check corresponding platform for all Timetable entries that aren't empty
9159  TName = TrackElementAt(1366, x).ActiveTrackElementName;
9160  TIMPair IMPair;
9161  bool FoundFlag = false;
9162  if(TName != "")
9163  {
9164  IMPair = GetVectorPositionsFromInactiveTrackMap(10, TrackElementAt(1367, x).HLoc, TrackElementAt(1368, x).VLoc, FoundFlag);
9165  if(FoundFlag)
9166  {
9167  if((InactiveTrackElementAt(17, IMPair.first).TrackType != Platform) && (InactiveTrackElementAt(18, IMPair.second).TrackType != Platform) &&
9169  {
9170  throw Exception("Track element with ActiveTrackElementName but no plat/named loc at H " + AnsiString(TrackElementAt(1369, x).HLoc) + " & V " +
9171  AnsiString(TrackElementAt(1370, x).VLoc) + " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
9172  }
9173  if((InactiveTrackElementAt(20, IMPair.first).LocationName != TName) && (InactiveTrackElementAt(21, IMPair.second).LocationName != TName))
9174  {
9175  throw Exception("Track element with ActiveTrackElementName " + TName + " but plat/named loc at H " + AnsiString(TrackElementAt(1371, x).HLoc) +
9176  " & V " + AnsiString(TrackElementAt(1372, x).VLoc) + " has different LocationName in CheckLocationNameMultiMap, caller = " +
9177  AnsiString(Caller));
9178  }
9179  }
9180  else
9181  {
9182  throw Exception("Track element with ActiveTrackElementName but no inactive element at H " + AnsiString(TrackElementAt(1373, x).HLoc) + " & V " +
9183  AnsiString(TrackElementAt(1374, x).VLoc) + " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
9184  }
9185  }
9186  }
9187  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
9188  {
9189  if(InactiveTrackElementAt(147, x).FixedNamedLocationElement)
9190  {
9191  SName = InactiveTrackElementAt(148, x).LocationName;
9192  SNIt = FindNamedElementInLocationNameMultiMap(6, SName, InactiveTrackVector.begin() + x, ErrorString);
9193  if(ErrorString != "")
9194  {
9195  throw Exception(ErrorString + " in CheckLocationNameMultiMap for InactiveTrackVector check, caller = " + AnsiString(Caller));
9196  }
9197  if(SNIt->second != (int)x)
9198  {
9199  throw Exception("Elements different in name map & TrackVector in CheckLocationNameMultiMap for TrackVector check, caller = " +
9200  AnsiString(Caller));
9201  }
9202  }
9203  }
9204  Utilities->CallLogPop(585);
9205 }
9206 
9207 // ---------------------------------------------------------------------------
9208 
9210  AnsiString &ErrorString)
9211 {
9212 /*
9213  Searches the name map to check if the element pointed to by the TTrackVectorIterator has the name
9214  LocationName. If it finds it the pointer TLocationNameMultiMapIterator is returned. If it fails ErrorString
9215  is set to an appropriate text to allow the calling function to report the error. Otherwise it is set to "".
9216 */
9217  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindNamedElementInLocationNameMultiMap," + LocationName + "," +
9218  AnsiString(TrackElement->HLoc) + "," + AnsiString(TrackElement->VLoc) + "," + AnsiString(TrackElement->SpeedTag));
9219  ErrorString = "";
9220  bool FoundFlag = false;
9221  TLocationNameMultiMapIterator SNIterator;
9222  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
9223 
9224  if(SNRange.first == SNRange.second)
9225  {
9226  ErrorString = "Error, Name " + LocationName + " not found in map";
9227  Utilities->CallLogPop(586);
9228  return(SNRange.first);
9229  }
9230  else
9231  {
9232  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
9233  {
9234  if(SNIterator->second < 0)
9235  {
9236  int TVPos = -1 - SNIterator->second;
9237  TTrackVectorIterator TVIt = TrackVector.begin() + TVPos;
9238  if(TVIt == TrackElement)
9239  {
9240  FoundFlag = true;
9241  Utilities->CallLogPop(587);
9242  return(SNIterator);
9243  }
9244  }
9245  else
9246  {
9247  int ITVPos = SNIterator->second;
9248  TTrackVectorIterator ITVIt = InactiveTrackVector.begin() + ITVPos;
9249  if(ITVIt == TrackElement)
9250  {
9251  FoundFlag = true;
9252  Utilities->CallLogPop(588);
9253  return(SNIterator);
9254  }
9255  }
9256  }
9257  }
9258  if(!FoundFlag)
9259  {
9260  ErrorString = "Error, Name " + LocationName + " found but not at required element";
9261  }
9262  Utilities->CallLogPop(589);
9263  return(SNIterator);
9264 }
9265 
9266 // ---------------------------------------------------------------------------
9267 
9268 void TTrack::ChangeLocationNameMultiMapEntry(int Caller, AnsiString NewName, TLocationNameMultiMapIterator SNIterator)
9269 {
9270 /*
9271  Changes the LocationName in the name multimap to NewName at the location pointed to by the TLocationNameMultiMapIterator
9272  from whatever it was before. Accepts null entries so that a formerly named element can have the name changed to "".
9273 */
9274  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ChangeLocationNameMultiMapEntry," + NewName);
9275  TLocationNameMultiMapEntry LocationNameEntry;
9276 
9277  LocationNameEntry.first = NewName;
9278  LocationNameEntry.second = SNIterator->second;
9279  LocationNameMultiMap.erase(SNIterator);
9280  LocationNameMultiMap.insert(LocationNameEntry);
9281  Utilities->CallLogPop(590);
9282 }
9283 
9284 // ---------------------------------------------------------------------------
9285 
9287 {
9288 // Takes an adjusted vector position value and returns a pointer to the relevant element. Can be in either vector.
9289  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackVectorIteratorFromNamePosition," + AnsiString(Position));
9290  if(Position < 0) // footcrossing
9291  {
9292  int TruePos = -1 - Position;
9293  // new check at v0.2b
9294  if(TrackElementAt(817, TruePos).TrackType != FootCrossing)
9295  {
9296  throw Exception("Footbridge/underpass error in GetTrackVectorIteratorFromNamePosition, caller = " + AnsiString(Caller));
9297  }
9298  Utilities->CallLogPop(591);
9299  return (TrackVector.begin() + TruePos);
9300  }
9301  else
9302  {
9303  // new check at v0.2b
9304  if(!(InactiveTrackElementAt(99, Position).FixedNamedLocationElement))
9305  {
9306  throw Exception("Inactive element error in GetTrackVectorIteratorFromNamePosition, caller = " + AnsiString(Caller));
9307  }
9308  Utilities->CallLogPop(592);
9309  return (InactiveTrackVector.begin() + Position);
9310  }
9311 }
9312 
9313 // ---------------------------------------------------------------------------
9314 
9315 void TTrack::DecrementValuesInInactiveTrackAndNameMaps(int Caller, unsigned int VecPos)
9316 {
9317 /*
9318  After an element has been erased from the inactive track vector, all the later elements are moved down one. This function
9319  decrements the position values for all values above that of the erased element in both InactiveTrack2MultiMap and
9320  LocationNameMultiMap.
9321 */
9322  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementValuesInInactiveTrackAndNameMaps," + AnsiString(VecPos));
9323  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator;
9324  TLocationNameMultiMapIterator LocationNameMultiMapIterator;
9325 
9326  if(!InactiveTrack2MultiMap.empty())
9327  {
9328  for(InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.begin(); InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end();
9329  InactiveTrack2MultiMapIterator++)
9330  {
9331  if(InactiveTrack2MultiMapIterator->second > VecPos)
9332  {
9333  InactiveTrack2MultiMapIterator->second--;
9334  }
9335  // can't be == VecPos as that position erased
9336  }
9337  }
9338  if(!LocationNameMultiMap.empty())
9339  {
9340  for(LocationNameMultiMapIterator = LocationNameMultiMap.begin(); LocationNameMultiMapIterator != LocationNameMultiMap.end();
9341  LocationNameMultiMapIterator++)
9342  {
9343  if(LocationNameMultiMapIterator->second < 0)
9344  {
9345  continue; // deal with TrackVectors separately
9346  }
9347  if(LocationNameMultiMapIterator->second > (int)VecPos)
9348  {
9349  LocationNameMultiMapIterator->second--;
9350  }
9351  }
9352  }
9353  Utilities->CallLogPop(593);
9354 }
9355 
9356 // ---------------------------------------------------------------------------
9357 
9358 void TTrack::DecrementValuesInGapsAndTrackAndNameMaps(int Caller, unsigned int VecPos)
9359 {
9360 /*
9361  After an element has been erased from the track vector, all the later elements are moved down one. This function
9362  decrements the position values for all values above that of the erased element in the gap elements, TrackMap and
9363  LocationNameMultiMap.
9364 */
9365  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementValuesInGapsAndTrackAndNameMaps," + AnsiString(VecPos));
9366  TTrackMapIterator TrackMapIterator;
9367  TLocationNameMultiMapIterator LocationNameMultiMapIterator;
9368 
9369  if(!TrackMap.empty())
9370  {
9371  for(TrackMapIterator = TrackMap.begin(); TrackMapIterator != TrackMap.end(); TrackMapIterator++)
9372  {
9373  if(TrackMapIterator->second > VecPos)
9374  {
9375  TrackMapIterator->second--;
9376  }
9377  // can't be == VecPos as that position erased
9378  }
9379  }
9380  if(!LocationNameMultiMap.empty())
9381  {
9382  for(LocationNameMultiMapIterator = LocationNameMultiMap.begin(); LocationNameMultiMapIterator != LocationNameMultiMap.end();
9383  LocationNameMultiMapIterator++)
9384  {
9385  if(LocationNameMultiMapIterator->second >= 0)
9386  {
9387  continue; // deal with InactiveTrackVectors separately
9388  }
9389  // (-1-VecPos) VP 0 1 2 3 4 5 6 7
9390  // Val -1 -2 -3 -4 -5 -6 -7 -8
9391  if(LocationNameMultiMapIterator->second < -(int)(VecPos + 1))
9392  {
9393  LocationNameMultiMapIterator->second++;
9394  }
9395  }
9396  }
9397  for(unsigned int x = 0; x < TrackVector.size(); x++)
9398  {
9399  TTrackElement &TkEl = TrackElementAt(1375, x); // no need to check so use this to speed up
9400  if(TkEl.TrackType == GapJump)
9401  {
9402  // position 0 is the gap
9403  if(TkEl.Conn[0] == int(VecPos))
9404  {
9405  TkEl.Conn[0] = -1; // connected to a deleted gap
9406  continue;
9407  }
9408  if(TkEl.Conn[0] > int(VecPos))
9409  {
9410  TkEl.Conn[0]--;
9411  }
9412  if(TkEl.Conn[0] > -1) // don't use 'else' here, need to check the value whether changed or not
9413  {
9414  if(TrackElementAt(709, TkEl.Conn[0]).TrackType != GapJump)
9415  {
9416  TkEl.Conn[0] = -1;
9417  }
9418  }
9419  }
9420  }
9421  Utilities->CallLogPop(1433);
9422 }
9423 
9424 // ---------------------------------------------------------------------------
9425 
9427 /*
9428  Clears the existing LocationNameMultiMap and rebuilds it from TrackVector and InactiveTrackVector. Called after the
9429  track is linked as many of the vector positions are likely to change - called from RepositionAndMapTrack();
9430  after names are changed in EraseLocationAndActiveTrackElementNames; and after the name changes in EnterLocationName.
9431 */
9432 {
9433  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildLocationNameMultiMap");
9434  LocationNameMultiMap.clear();
9435  TLocationNameMultiMapEntry LocationNameEntry;
9436  TTrackElement TrackElement;
9437 
9438  for(unsigned int TVPos = 0; TVPos < TrackVector.size(); TVPos++)
9439  {
9440  TrackElement = TrackElementAt(1376, TVPos);
9441  if(TrackElement.FixedNamedLocationElement)
9442  {
9443  LocationNameEntry.first = TrackElement.LocationName;
9444  LocationNameEntry.second = -1 - TVPos; // adjusted for footcrossings
9445  LocationNameMultiMap.insert(LocationNameEntry);
9446  }
9447  }
9448 
9449  for(unsigned int ITVPos = 0; ITVPos < InactiveTrackVector.size(); ITVPos++)
9450  {
9451  TrackElement = InactiveTrackElementAt(149, ITVPos);
9452  if(TrackElement.FixedNamedLocationElement)
9453  {
9454  LocationNameEntry.first = TrackElement.LocationName;
9455  LocationNameEntry.second = ITVPos;
9456  LocationNameMultiMap.insert(LocationNameEntry);
9457  }
9458  }
9459  Utilities->CallLogPop(594);
9460 }
9461 
9462 // ---------------------------------------------------------------------------
9463 
9465 // Return true if there is a named location present in the railway
9466 // ignores lone footcrossings, can't name these on their own & track won't link if there are any
9467 {
9468  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NonFootCrossingNamedLocationExists");
9469  TTrackVectorIterator ITVI;
9470 
9471  if(InactiveTrackVector.empty())
9472  {
9473  Utilities->CallLogPop(1343);
9474  return(false);
9475  }
9476  for(ITVI = InactiveTrackVector.begin(); ITVI != InactiveTrackVector.end(); ITVI++)
9477  {
9478  if((ITVI->TrackType == Platform) || (ITVI->TrackType == NamedNonStationLocation) || (ITVI->TrackType == Concourse))
9479  {
9480  Utilities->CallLogPop(1404);
9481  return(true);
9482  }
9483  }
9484  Utilities->CallLogPop(1344);
9485  return(false);
9486 }
9487 
9488 // ---------------------------------------------------------------------------
9489 
9491 /*
9492  Work through all elements in TrackVector setting all lengths & speed limits to default values - including both tracks for 2-track elements
9493 */
9494 {
9495  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetAllDefaultLengthsAndSpeedLimits");
9496 // ResetDistanceElements(6);
9497  for(unsigned int x = 0; x < TrackVector.size(); x++)
9498  {
9499  TTrackElement &TE = TrackElementAt(718, x);
9502  if((TE.TrackType == Points) || (TE.TrackType == Crossover) || (TE.TrackType == Bridge))
9503  {
9506  }
9507  }
9508 /* old function
9509  if((TrackElementAt(, x).TrackType == Points) || (TrackElementAt(, x).TrackType == Crossover) || (TrackElementAt(, x).TrackType == Bridge))
9510  {
9511  SetOneDefaultTrackLength(2, TrackElementAt(, x), 0);
9512  SetOneDefaultTrackLength(3, TrackElementAt(, x), 2);
9513  }
9514  else
9515  {
9516  SetOneDefaultTrackLength(4, TrackElementAt(, x), 0);
9517  }
9518  }
9519 */
9520  Utilities->CallLogPop(617);
9521 }
9522 
9523 // ---------------------------------------------------------------------------
9524 
9525 void TTrack::LengthMarker(int Caller, TDisplay *Disp)
9526 // Examine all elements in the TrackVector and if have a valid length mark the relevant track using MarkOneLength.
9527 {
9528  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LengthMarker");
9529  for(unsigned int x = 0; x < TrackVector.size(); x++)
9530  {
9531  TTrackElement TempElement = TrackElementAt(1377, x);
9532  if(TempElement.Length01 > -1)
9533  {
9534  MarkOneLength(1, TempElement, true, Disp); // need Length01 test in case there are erase elements (but shouldn't be after LinkTrack)
9535  }
9536  if(TempElement.Length23 > -1)
9537  {
9538  MarkOneLength(2, TempElement, false, Disp);
9539  }
9540  }
9541  Disp->Update();
9542  Utilities->CallLogPop(618);
9543 }
9544 
9545 // ---------------------------------------------------------------------------
9546 
9547 void TTrack::MarkOneLength(int Caller, TTrackElement TrackElement, bool FirstTrack, TDisplay *Disp)
9548 /*
9549  Rule: Only marked if different in any way from the default values - length 100m and speed limit 200km/h normally but can be changed in Config.txt
9550  First check using IsElementTrackDefaultLength whether the relevant track is already set to the default values, and if so
9551  return as nothing further to do. Otherwise pick up the appropriate bitmap (using the AutoSigRouteGraphicsPtr bitmaps)
9552  using the same technique as in TPrefDirElement::EntryExitNumber() & *TPrefDirElement::GetPrefDirGraphicPtr(), for the relevant
9553  track as indicated by FirstTrack (true for track01 & false for track23).
9554 */
9555 {
9556  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MarkOneLength," + TrackElement.LogTrack(8) + "," +
9557  AnsiString((short)FirstTrack));
9558  bool LengthDifferent = false, SpeedDifferent = false;
9559 
9560  if(IsElementDefaultLength(1, TrackElement, FirstTrack, LengthDifferent, SpeedDifferent))
9561  {
9562  Utilities->CallLogPop(619);
9563  return;
9564  }
9565  int EXArray[16][2] =
9566  {{4, 6}, {2, 8}, // horizontal & vertical
9567  {2, 4}, {6, 2}, {8, 6}, {4, 8}, // sharp curves
9568  {1, 6}, {3, 8}, {9, 4}, {7, 2}, {1, 8}, {3, 4}, {9, 2}, {7, 6}, // loose curves
9569  {1, 9}, {3, 7}}; // forward & reverse diagonals
9570 
9571  int Index = -1, BrNum = -1, GrNum = -1, InLink, OutLink;
9572  Graphics::TBitmap *Bitmap;
9573 
9574  if(FirstTrack)
9575  {
9576  InLink = TrackElement.Link[0];
9577  OutLink = TrackElement.Link[1];
9578  }
9579  else
9580  {
9581  InLink = TrackElement.Link[2];
9582  OutLink = TrackElement.Link[3];
9583  }
9584  for(int x = 0; x < 16; x++)
9585  {
9586  if((InLink == EXArray[x][0] && OutLink == EXArray[x][1]) || (InLink == EXArray[x][1] && OutLink == EXArray[x][0]))
9587  {
9588  Index = x;
9589  }
9590  }
9591  if(Index == -1)
9592  {
9593  throw Exception("Error, failed to find Index in TTrack::MarkOneLength");
9594  }
9595 /* The order for bridge entries & exits is as below. Note that there are 3 of each type,
9596  the graphic for each of which is different because of the shape of the overbridge. The basic
9597  entry/exit value is computed above, and this used to select only from elements with that entry/exit
9598  value that is an underbridge, i.e overbridges ignored as the normal graphic is OK for them.
9599  int BrEXArray[24][2] = {
9600  {4,6},{2,8},{1,9},{3,7},
9601  {1,9},{3,7},{1,9},{3,7},
9602  {2,8},{4,6},{2,8},{4,6}
9603 */
9604  if(!FirstTrack && (TrackElement.TrackType == Bridge))
9605  {
9606  if(Index == 1)
9607  {
9608  if(TrackElement.SpeedTag == 49)
9609  {
9610  BrNum = 1 + 16;
9611  }
9612  else if(TrackElement.SpeedTag == 54)
9613  {
9614  BrNum = 8 + 16;
9615  }
9616  else if(TrackElement.SpeedTag == 55)
9617  {
9618  BrNum = 10 + 16;
9619  }
9620  }
9621  else if(Index == 0)
9622  {
9623  if(TrackElement.SpeedTag == 48)
9624  {
9625  BrNum = 0 + 16;
9626  }
9627  else if(TrackElement.SpeedTag == 58)
9628  {
9629  BrNum = 11 + 16;
9630  }
9631  else if(TrackElement.SpeedTag == 59)
9632  {
9633  BrNum = 9 + 16;
9634  }
9635  }
9636  else if(Index == 14)
9637  {
9638  if(TrackElement.SpeedTag == 50)
9639  {
9640  BrNum = 2 + 16;
9641  }
9642  else if(TrackElement.SpeedTag == 52)
9643  {
9644  BrNum = 4 + 16;
9645  }
9646  else if(TrackElement.SpeedTag == 57)
9647  {
9648  BrNum = 6 + 16;
9649  }
9650  }
9651  else if(Index == 15)
9652  {
9653  if(TrackElement.SpeedTag == 51)
9654  {
9655  BrNum = 3 + 16;
9656  }
9657  else if(TrackElement.SpeedTag == 53)
9658  {
9659  BrNum = 7 + 16;
9660  }
9661  else if(TrackElement.SpeedTag == 56)
9662  {
9663  BrNum = 5 + 16;
9664  }
9665  }
9666  }
9667  if(!FirstTrack && (TrackElement.TrackType == Bridge))
9668  {
9669  GrNum = BrNum;
9670  }
9671  else
9672  {
9673  GrNum = Index;
9674  }
9675  if(LengthDifferent && SpeedDifferent) // blue - use autosig graphics
9676  {
9677  if(GrNum > 15) // underbridge
9678  {
9679  Bitmap = RailGraphics->BridgeRouteAutoSigsGraphicsPtr[GrNum - 16];
9680  }
9681  else
9682  {
9683  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[GrNum];
9684  }
9685  if(TrackElement.SpeedTag == 64)
9686  {
9687  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
9688  }
9689  if(TrackElement.SpeedTag == 65)
9690  {
9692  }
9693  if(TrackElement.SpeedTag == 66)
9694  {
9696  }
9697  if(TrackElement.SpeedTag == 67)
9698  {
9700  }
9701  if(TrackElement.SpeedTag == 80)
9702  {
9703  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]; // intercept continuations to show the dots
9704  }
9705  if(TrackElement.SpeedTag == 81)
9706  {
9708  }
9709  if(TrackElement.SpeedTag == 82)
9710  {
9712  }
9713  if(TrackElement.SpeedTag == 83)
9714  {
9716  }
9717  if(TrackElement.SpeedTag == 84)
9718  {
9720  }
9721  if(TrackElement.SpeedTag == 85)
9722  {
9724  }
9725  if(TrackElement.SpeedTag == 86)
9726  {
9728  }
9729  if(TrackElement.SpeedTag == 87)
9730  {
9732  }
9733  if(TrackElement.SpeedTag == 129)
9734  {
9735  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]; // intercept under footbridges
9736  }
9737  if(TrackElement.SpeedTag == 130)
9738  {
9740  }
9741  }
9742 
9743  else if(LengthDifferent && !SpeedDifferent) // green - use pref sig graphics
9744  {
9745  if(GrNum > 15) // underbridge
9746  {
9747  Bitmap = RailGraphics->BridgeSigRouteGraphicsPtr[GrNum - 16];
9748  }
9749  else
9750  {
9751  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[GrNum];
9752  }
9753  if(TrackElement.SpeedTag == 64)
9754  {
9755  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
9756  }
9757  if(TrackElement.SpeedTag == 65)
9758  {
9759  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[17];
9760  }
9761  if(TrackElement.SpeedTag == 66)
9762  {
9763  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[18];
9764  }
9765  if(TrackElement.SpeedTag == 67)
9766  {
9767  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[19];
9768  }
9769  if(TrackElement.SpeedTag == 80)
9770  {
9771  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[20]; // intercept continuations to show the dots
9772  }
9773  if(TrackElement.SpeedTag == 81)
9774  {
9775  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[21];
9776  }
9777  if(TrackElement.SpeedTag == 82)
9778  {
9779  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[22];
9780  }
9781  if(TrackElement.SpeedTag == 83)
9782  {
9783  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[23];
9784  }
9785  if(TrackElement.SpeedTag == 84)
9786  {
9787  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[24];
9788  }
9789  if(TrackElement.SpeedTag == 85)
9790  {
9791  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[25];
9792  }
9793  if(TrackElement.SpeedTag == 86)
9794  {
9795  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[26];
9796  }
9797  if(TrackElement.SpeedTag == 87)
9798  {
9799  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[27];
9800  }
9801  if(TrackElement.SpeedTag == 129)
9802  {
9803  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[28]; // intercept under footbridges
9804  }
9805  if(TrackElement.SpeedTag == 130)
9806  {
9807  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[29];
9808  }
9809  }
9810 
9811  else // SpeedDifferent only: red - use non sig graphics
9812  {
9813  if(GrNum > 15) // underbridge
9814  {
9815  Bitmap = RailGraphics->BridgeNonSigRouteGraphicsPtr[GrNum - 16];
9816  }
9817  else
9818  {
9819  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[GrNum];
9820  }
9821  if(TrackElement.SpeedTag == 64)
9822  {
9823  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
9824  }
9825  if(TrackElement.SpeedTag == 65)
9826  {
9828  }
9829  if(TrackElement.SpeedTag == 66)
9830  {
9832  }
9833  if(TrackElement.SpeedTag == 67)
9834  {
9836  }
9837  if(TrackElement.SpeedTag == 80)
9838  {
9839  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[20]; // intercept continuations to show the dots
9840  }
9841  if(TrackElement.SpeedTag == 81)
9842  {
9844  }
9845  if(TrackElement.SpeedTag == 82)
9846  {
9848  }
9849  if(TrackElement.SpeedTag == 83)
9850  {
9852  }
9853  if(TrackElement.SpeedTag == 84)
9854  {
9856  }
9857  if(TrackElement.SpeedTag == 85)
9858  {
9860  }
9861  if(TrackElement.SpeedTag == 86)
9862  {
9864  }
9865  if(TrackElement.SpeedTag == 87)
9866  {
9868  }
9869  if(TrackElement.SpeedTag == 129)
9870  {
9871  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[28]; // intercept under footbridges
9872  }
9873  if(TrackElement.SpeedTag == 130)
9874  {
9876  }
9877  }
9878  Disp->PlotOutput(67, TrackElement.HLoc * 16, TrackElement.VLoc * 16, Bitmap);
9879  Utilities->CallLogPop(620);
9880 }
9881 
9882 // ---------------------------------------------------------------------------
9883 
9884 bool TTrack::IsElementDefaultLength(int Caller, TTrackElement &TrackElement, bool FirstTrack, bool &LengthDifferent, bool &SpeedDifferent)
9885 /* FirstTrack = LinkPos's 0 & 1
9886  Examine track within TrackElement & check whether it has the default length and speed limit, return true if so
9887 */
9888 {
9889  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsElementTrackDefaultLength," + TrackElement.LogTrack(10) + "," +
9890  AnsiString((short)FirstTrack));
9891  LengthDifferent = false;
9892  SpeedDifferent = false;
9893  if(((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover)) && FirstTrack)
9894  {
9895  if(TrackElement.Length01 != DefaultTrackLength)
9896  {
9897  LengthDifferent = true;
9898  }
9899  if(TrackElement.SpeedLimit01 != DefaultTrackSpeedLimit)
9900  {
9901  SpeedDifferent = true;
9902  }
9903  if(LengthDifferent || SpeedDifferent)
9904  {
9905  Utilities->CallLogPop(625);
9906  return(false);
9907  }
9908  Utilities->CallLogPop(626);
9909  return(true);
9910  }
9911 
9912  else if(((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover)) && !FirstTrack)
9913  {
9914  if(TrackElement.Length23 != DefaultTrackLength)
9915  {
9916  LengthDifferent = true;
9917  }
9918  if(TrackElement.SpeedLimit23 != DefaultTrackSpeedLimit)
9919  {
9920  SpeedDifferent = true;
9921  }
9922  if(LengthDifferent || SpeedDifferent)
9923  {
9924  Utilities->CallLogPop(627);
9925  return(false);
9926  }
9927  Utilities->CallLogPop(628);
9928  return(true);
9929  }
9930 
9931  else // any other 1 track element, including platforms being present
9932  {
9933  if(TrackElement.Length01 != DefaultTrackLength)
9934  {
9935  LengthDifferent = true;
9936  }
9937  if(TrackElement.SpeedLimit01 != DefaultTrackSpeedLimit)
9938  {
9939  SpeedDifferent = true;
9940  }
9941  if(LengthDifferent || SpeedDifferent)
9942  {
9943  Utilities->CallLogPop(629);
9944  return(false);
9945  }
9946  Utilities->CallLogPop(630);
9947  return(true);
9948  }
9949 }
9950 
9951 // ---------------------------------------------------------------------------
9952 
9953 bool TTrack::IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
9954 // Check whether there is a platform or NamedNonStationLocation present at HLoc & VLoc, return true if so
9955 {
9956  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsPlatformOrNamedNonStationLocationPresent," + AnsiString(HLoc) + "," +
9957  AnsiString(VLoc));
9958  bool FoundFlag;
9959  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(11, HLoc, VLoc, FoundFlag);
9960 
9961  if(!FoundFlag)
9962  {
9963  Utilities->CallLogPop(633);
9964  return(false);
9965  }
9966  if((InactiveTrackElementAt(42, IMPair.first).TrackType == Platform) || (InactiveTrackElementAt(91, IMPair.first).TrackType == NamedNonStationLocation))
9967  {
9968  Utilities->CallLogPop(634);
9969  return(true); // only need to check first since if second is a platform the the first must be too
9970  }
9971  else
9972  {
9973  Utilities->CallLogPop(635);
9974  return(false);
9975  }
9976 }
9977 
9978 // ---------------------------------------------------------------------------
9979 
9980 bool TTrack::IsNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
9981 // Check whether there is a NamedNonStationLocation present at HLoc & VLoc, return true if so
9982 {
9983  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsNamedNonStationLocationPresent," + AnsiString(HLoc) + "," +
9984  AnsiString(VLoc));
9985  bool FoundFlag;
9986  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(12, HLoc, VLoc, FoundFlag);
9987 
9988  if(!FoundFlag)
9989  {
9990  Utilities->CallLogPop(636);
9991  return(false);
9992  }
9994  {
9995  Utilities->CallLogPop(637);
9996  return(true); // only need to check first since only one used for NamedNonStationLocations
9997  }
9998  else
9999  {
10000  Utilities->CallLogPop(638);
10001  return(false);
10002  }
10003 }
10004 
10005 // ---------------------------------------------------------------------------
10006 
10008 /* Called when trying to link track and when a name changed when track already linked. Examines all track elements that
10009  have ActiveTrackElementName set, sums the number of consecutive elements with the same name, and sets the EntryLink values for
10010  the front of train stop points for each direction.
10011  For stations (not non-station named locations) of length n, where n > 1, stop element is [floor((n+1)/2) + 1] from each
10012  end (unless buffers at one or both ends in which case stop points are the end elements).
10013  Note that for a single element the stop point is the element itself (formula doesn't apply).
10014  During the function the StationEntryStopLink values are set to 5 if not used, so no need to keep
10015  repeating the procedure for every element. At the end all unused values are returned to -1.
10016  For NamedNonStationLocations the stop points are at the end elements to allow trains to stack up.
10017 */
10018 {
10019  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetStationEntryStopLinkPosses");
10020  TTrackElement TempElement, StartElement;
10021  AnsiString TempName;
10022  int VecPos, StartVecPos, Count, EntryPos, StartEntryPos, ForwardNumber, ReverseNumber;
10023  bool ForwardSet, ReverseSet;
10024 
10025  for(unsigned int x = 0; x < TrackVector.size(); x++)
10026  {
10029  }
10030  for(unsigned int x = 0; x < TrackVector.size(); x++)
10031  {
10032  ForwardSet = false;
10033  ReverseSet = false;
10034  TempElement = TrackElementAt(1380, x);
10035  VecPos = x;
10036  if((TempElement.ActiveTrackElementName != "") && (TempElement.StationEntryStopLinkPos1 == -1))
10037  // 2nd condition incl so don't re-examine elements with stop links set to 5
10038  {
10039  TempName = TempElement.ActiveTrackElementName;
10040  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(44, TempElement.Conn[0]).ActiveTrackElementName == TempName) &&
10041  (TrackElementAt(45, TempElement.Conn[1]).ActiveTrackElementName == TempName))
10042  // an element linked at both ends where both links are also named elements
10043  // only Conn[0] & [1] relevant for ActiveTrackElementName elements (only 2-track named element is points, and only straight track relevant & this has 0 & 1 as entry/exit positions)
10044  {
10045  continue; // looking for an end element so skip this one
10046  }
10047  else // reached one end
10048  {
10049  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(46, TempElement.Conn[0]).ActiveTrackElementName != TempName) &&
10050  (TrackElementAt(47, TempElement.Conn[1]).ActiveTrackElementName != TempName))
10051  // single named element linked at both ends
10052  {
10053  TrackElementAt(48, VecPos).StationEntryStopLinkPos1 = 0;
10054  TrackElementAt(49, VecPos).StationEntryStopLinkPos2 = 1;
10055  continue;
10056  }
10057  else if((TempElement.TrackType == Buffers) && (TrackElementAt(618, TempElement.Conn[1]).ActiveTrackElementName != TempName))
10058  // single named buffer element (LinkPos 1 is the non-buffer end)
10059  {
10060  TrackElementAt(619, VecPos).StationEntryStopLinkPos1 = 0;
10061  TrackElementAt(620, VecPos).StationEntryStopLinkPos2 = 1;
10062  continue;
10063  }
10064  else
10065  // Note: only interested in connection positions 0 & 1 since all named elements are single track except points,
10066  // and platforms always on straight (conns 0 & 1) section of points
10067  {
10068  for(int y = 0; y < 2; y++)
10069  {
10070  int Dir = y; // Dir is the ExitPos of the element, towards the rest of the named elements
10071  // check for buffers at both ends - no need, function below now covers buffers at one & both ends
10072 /* TTrackElement Temp1 = TempElement;
10073  ***********New section, compiles but not checked - does bit below need to be else if?
10074  if((Temp1.TrackType == Buffers) && (Temp1.GetConfig(Dir) != End))
10075  {
10076  //search along Dir direction until find other end, skip if Dir facing buffer end
10077  int NewDir = Dir;
10078  int NewVecPos;
10079  while((Temp1.Conn[NewDir] > -1) && (TrackElementAt(598, Temp1.Conn[NewDir]).ActiveTrackElementName == TempName))
10080  {
10081  NewVecPos = Temp1.Conn[NewDir];
10082  NewDir = Track->GetNonPointsOppositeLinkPos(Temp1.ConnLinkPos[NewDir]);
10083  Temp1 = TrackElementAt(601, NewVecPos);
10084  }
10085  if((Temp1.Conn[NewDir] == -1) && (Temp1.TrackType == Buffers))
10086  {
10087  TrackElementAt(599, VecPos).StationEntryStopLinkPos1 = Dir;//EntryPos for train coming from other end is Dir
10088  TrackElementAt(600, NewVecPos).StationEntryStopLinkPos2 = 1 - NewDir;//For train moving in same direction as search direction its EntryPos == 1 - NewDir since NewDir is the ExitPos
10089  }
10090  }
10091  ***************
10092 */
10093  // end may be linked at both ends but only one link named, or buffer with linked element named
10094  // if a buffer then the named linkpos has to be 1
10095  // already dealt with all types of single element so at least 2 linked named element
10096  if(((TempElement.Conn[Dir] > -1) && (TempElement.Conn[1 - Dir] > -1) && (TrackElementAt(50,
10097  TempElement.Conn[1 - Dir]).ActiveTrackElementName != TempName)) || ((TempElement.TrackType == Buffers) && (Dir == 1)))
10098  {
10099  StartElement = TempElement;
10100  StartVecPos = VecPos;
10101  TrackElementAt(51, VecPos).StationEntryStopLinkPos1 = 5; // set to 5 to stop re-examination in later searches, all set back at end
10102  TrackElementAt(52, VecPos).StationEntryStopLinkPos2 = 5;
10103  EntryPos = 1 - Dir;
10104  StartEntryPos = 1 - Dir;
10105  Count = 1;
10106  // work along named elements until find the other end
10107  while((TempElement.Conn[1 - EntryPos] > -1) && (TrackElementAt(53,
10108  TempElement.Conn[1 - EntryPos]).ActiveTrackElementName == TempName))
10109  // at end of 'while' Count = length (in elements) of platform/nonstationloc, VecPos = vector number of far end
10110  // which is the last named element that is track-linked to the rest of the location, it may be a buffer
10111  // all stop link pos's are set to 5
10112  {
10113  VecPos = TempElement.Conn[1 - EntryPos];
10114  int TempEntryPos = TempElement.ConnLinkPos[1 - EntryPos];
10115  TempElement = TrackElementAt(54, TempElement.Conn[1 - EntryPos]);
10116  EntryPos = TempEntryPos;
10117  Count++;
10118  TrackElementAt(55, VecPos).StationEntryStopLinkPos1 = 5;
10119  TrackElementAt(56, VecPos).StationEntryStopLinkPos2 = 5;
10120  }
10121  // here when reached other end, maybe buffers, continuation or last named linked element
10122  if(TrackElementAt(57, VecPos).TrackType == Buffers)
10123  // terminal station, set end elements as stop elements
10124  {
10125  TrackElementAt(58, VecPos).StationEntryStopLinkPos1 = EntryPos;
10126  TrackElementAt(59, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos; // for train leaving
10127  continue;
10128  }
10129  if(TrackElementAt(60, StartVecPos).TrackType == Buffers) // best not to use 'else if' as both ends could be buffers!
10130  // terminal station, set end elements as stop elements
10131  {
10132  TrackElementAt(61, VecPos).StationEntryStopLinkPos1 = EntryPos;
10133  TrackElementAt(62, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos;
10134  continue;
10135  }
10136  if(IsNamedNonStationLocationPresent(1, TrackElementAt(63, StartVecPos).HLoc, TrackElementAt(64, StartVecPos).VLoc))
10137  // NonStationLocation so set end elements as stop elements
10138  {
10139  TrackElementAt(65, VecPos).StationEntryStopLinkPos1 = EntryPos;
10140  TrackElementAt(66, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos;
10141  continue;
10142  }
10143  // now Count == length of platform, can calculate StationEntryStopLinkPos values and the elements to which they apply
10144  ForwardNumber = ((Count + 1) / 2) + 1;
10145  ReverseNumber = (Count - ForwardNumber) + 1;
10146  Count = 1; // starting value
10147  EntryPos = 1 - Dir;
10148  TempElement = StartElement;
10149  VecPos = StartVecPos;
10150  if(Count == ForwardNumber)
10151  {
10152  TrackElementAt(67, VecPos).StationEntryStopLinkPos1 = EntryPos;
10153  ForwardSet = true;
10154  }
10155  if(Count == ReverseNumber) // don't use 'else' as may both be at same element
10156  {
10157  TrackElementAt(68, VecPos).StationEntryStopLinkPos2 = 1 - EntryPos;
10158  ReverseSet = true;
10159  }
10160  while((TempElement.Conn[1 - EntryPos] > -1) && (TrackElementAt(69,
10161  TempElement.Conn[1 - EntryPos]).ActiveTrackElementName == TempName) && (!ForwardSet || !ReverseSet))
10162  {
10163  VecPos = TempElement.Conn[1 - EntryPos];
10164  int TempEntryPos = TempElement.ConnLinkPos[1 - EntryPos];
10165  TempElement = TrackElementAt(70, TempElement.Conn[1 - EntryPos]);
10166  EntryPos = TempEntryPos;
10167  Count++;
10168  if(Count == ForwardNumber)
10169  {
10170  TrackElementAt(71, VecPos).StationEntryStopLinkPos1 = EntryPos;
10171  ForwardSet = true;
10172  }
10173  if(Count == ReverseNumber)
10174  {
10175  TrackElementAt(72, VecPos).StationEntryStopLinkPos2 = 1 - EntryPos;
10176  ReverseSet = true;
10177  }
10178  }
10179  }
10180  }
10181  }
10182  }
10183  }
10184  }
10185  for(unsigned int x = 0; x < TrackVector.size(); x++)
10186  {
10187  if(TrackElementAt(1381, x).StationEntryStopLinkPos1 == 5)
10188  {
10190  }
10191  if(TrackElementAt(1383, x).StationEntryStopLinkPos2 == 5)
10192  {
10194  }
10195  }
10196  Utilities->CallLogPop(639);
10197 }
10198 
10199 // ---------------------------------------------------------------------------
10200 
10201 void TTrack::PlotSmallRailway(int Caller, TDisplay *Disp)
10202 {
10203  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallRailway");
10204  TTrackElement Next;
10205 
10207  while(ReturnNextInactiveTrackElement(1, Next))
10208  {
10209  if(Next.SmallGraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
10210  {
10211  if(((Next.TrackType == Platform) || (Next.TrackType == Concourse) || (Next.TrackType == NamedNonStationLocation)) && (Next.LocationName == ""))
10212  // need striped graphics
10213  {
10214  if(Next.SpeedTag == 76)
10215  {
10216  Disp->PlotSmallOutput(11, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm76striped);
10217  }
10218  else if(Next.SpeedTag == 77)
10219  {
10220  Disp->PlotSmallOutput(12, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm77striped);
10221  }
10222  else if(Next.SpeedTag == 78)
10223  {
10224  Disp->PlotSmallOutput(13, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm78striped);
10225  }
10226  else if(Next.SpeedTag == 79)
10227  {
10228  Disp->PlotSmallOutput(14, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm79striped);
10229  }
10230  else if(Next.SpeedTag == 96)
10231  {
10232  Disp->PlotSmallOutput(15, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm96striped);
10233  }
10234  else if(Next.SpeedTag == 131)
10235  {
10236  Disp->PlotSmallOutput(16, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm131striped);
10237  }
10238  }
10239  else
10240  {
10241  Disp->PlotSmallOutput(17, Next.HLoc * 4, (Next.VLoc * 4), Next.SmallGraphicPtr);
10242  }
10243  }
10244  }
10245 
10246  NextTrackElementPtr = TrackVector.begin();
10247  while(ReturnNextTrackElement(1, Next))
10248  {
10249  if(Next.SmallGraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
10250  {
10251  if((Next.TrackType == FootCrossing) && (Next.LocationName == "")) // need striped graphics, use sm129 & 130 for 145 & 146
10252  {
10253  if((Next.SpeedTag == 129) || (Next.SpeedTag == 145))
10254  {
10255  Disp->PlotSmallOutput(18, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm129striped);
10256  }
10257  else if((Next.SpeedTag == 130) || (Next.SpeedTag == 146))
10258  {
10259  Disp->PlotSmallOutput(19, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm130striped);
10260  }
10261  }
10262  else
10263  {
10264  Disp->PlotSmallOutput(20, Next.HLoc * 4, (Next.VLoc * 4), Next.SmallGraphicPtr);
10265  }
10266  }
10267  }
10268  Disp->Update();
10269  Utilities->CallLogPop(640);
10270 }
10271 
10272 // ---------------------------------------------------------------------------
10273 
10274 void TTrack::PlotSmallRedGap(int Caller)
10275 {
10276  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallRedGap");
10278  Utilities->CallLogPop(1346);
10279 }
10280 
10281 // ---------------------------------------------------------------------------
10282 
10283 void TTrack::TrackClear(int Caller)
10284 {
10285  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackClear");
10286  TrackVector.clear();
10287  InactiveTrackVector.clear();
10288  TrackMap.clear();
10290  if(TextHandler->TextVector.size() == 0)
10291  {
10292  Display->DisplayOffsetH = 0;
10293  Display->DisplayOffsetV = 0;
10300  HLocMin = 2000000000;
10301  HLocMax = -2000000000;
10302  VLocMin = 2000000000;
10303  VLocMax = -2000000000;
10304  }
10305  else
10306  {
10307  CalcHLocMinEtc(4);
10308  }
10309  Utilities->CallLogPop(1347);
10310 }
10311 
10312 // ---------------------------------------------------------------------------
10313 
10314 void TTrack::CalcHLocMinEtc(int Caller)
10315 {
10316  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CalcHLocMinEtc");
10317  HLocMin = 2000000000;
10318  VLocMin = 2000000000;
10319  HLocMax = -2000000000;
10320  VLocMax = -2000000000;
10321  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
10322  {
10323  if(TrackElementAt(1385, x).SpeedTag == 0)
10324  {
10325  continue; // skip erase elements or would interfere with Min & Max values
10326  }
10327  if(TrackElementAt(1386, x).HLoc - 1 < HLocMin)
10328  {
10329  HLocMin = TrackElementAt(1387, x).HLoc - 1; // add one all round
10330  }
10331  if(TrackElementAt(1388, x).HLoc + 1 > HLocMax)
10332  {
10333  HLocMax = TrackElementAt(1389, x).HLoc + 1;
10334  }
10335  if(TrackElementAt(1390, x).VLoc - 1 < VLocMin)
10336  {
10337  VLocMin = TrackElementAt(1391, x).VLoc - 1;
10338  }
10339  if(TrackElementAt(1392, x).VLoc + 1 > VLocMax)
10340  {
10341  VLocMax = TrackElementAt(1393, x).VLoc + 1;
10342  }
10343  }
10344  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++) // check all elements in turn
10345  {
10346  if(InactiveTrackElementAt(150, x).SpeedTag == 0)
10347  {
10348  continue; // shouldn't be any inactive erase elements but include anyway
10349  }
10350  if(InactiveTrackElementAt(151, x).HLoc - 1 < HLocMin)
10351  {
10352  HLocMin = InactiveTrackElementAt(152, x).HLoc - 1; // add one all round
10353  }
10354  if(InactiveTrackElementAt(153, x).HLoc + 1 > HLocMax)
10355  {
10356  HLocMax = InactiveTrackElementAt(162, x).HLoc + 1;
10357  }
10358  if(InactiveTrackElementAt(154, x).VLoc - 1 < VLocMin)
10359  {
10360  VLocMin = InactiveTrackElementAt(155, x).VLoc - 1;
10361  }
10362  if(InactiveTrackElementAt(156, x).VLoc + 1 > VLocMax)
10363  {
10364  VLocMax = InactiveTrackElementAt(157, x).VLoc + 1;
10365  }
10366  }
10367  for(unsigned int x = 0; x < TextHandler->TextVectorSize(10); x++) // check all elements in turn
10368  {
10369 /* Removed at v2.2.0: It isn't needed because null names aren't entered into vector, and in any case if were then
10370  will fail as x will exceed the maximum value
10371  if(TextHandler->TextPtrAt(, x)->TextString == "")
10372  {
10373  TextHandler->TextErase(, TextHandler->TextPtrAt(35, x)->HPos, TextHandler->TextPtrAt(36, x)->VPos);
10374  }
10375 */
10376  int TextH = TextHandler->TextPtrAt(0, x)->HPos, TextV = TextHandler->TextPtrAt(1, x)->VPos;
10377  if((TextH / 16) - 1 < HLocMin)
10378  {
10379  HLocMin = (TextH / 16) - 1; // integer division will truncate so subtract 1 to ensure include the start
10380  }
10381  if((TextH / 16) + 1 > HLocMax)
10382  {
10383  HLocMax = (TextH / 16) + 1; // integer division will truncate so add 1 to ensure include the start
10384  }
10385  if((TextV / 16) - 1 < VLocMin)
10386  {
10387  VLocMin = (TextV / 16) - 1;
10388  }
10389  if((TextV / 16) + 1 > VLocMax)
10390  {
10391  VLocMax = (TextV / 16) + 1;
10392  }
10393  }
10394  for(unsigned int x = 0; x < UserGraphicVector.size(); x++) // added at v2.4.0
10395  {
10396  if((UserGraphicVectorAt(5, x).HPos / 16) - 1 < HLocMin)
10397  {
10398  HLocMin = (UserGraphicVectorAt(6, x).HPos / 16) - 1; // add one all round
10399  }
10400  if(((UserGraphicVectorAt(7, x).HPos + UserGraphicVectorAt(8, x).Width) / 16) + 1 > HLocMax)
10401  {
10402  HLocMax = ((UserGraphicVectorAt(9, x).HPos + UserGraphicVectorAt(10, x).Width) / 16) + 1;
10403  }
10404  if((UserGraphicVectorAt(11, x).VPos / 16) - 1 < VLocMin)
10405  {
10406  VLocMin = (UserGraphicVectorAt(12, x).VPos / 16) - 1;
10407  }
10408  if(((UserGraphicVectorAt(13, x).VPos + UserGraphicVectorAt(14, x).Height) / 16) + 1 > VLocMax)
10409  {
10410  VLocMax = ((UserGraphicVectorAt(15, x).VPos + UserGraphicVectorAt(16, x).Height) / 16) + 1;
10411  }
10412  }
10413 
10414  Utilities->CallLogPop(641);
10415 }
10416 
10417 // ---------------------------------------------------------------------------
10418 
10419 void TTrack::UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos,
10420  bool &UserGraphicFoundFlag)
10421 {
10422  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UserGraphicMove," + AnsiString(HPosInput) + "," + AnsiString(VPosInput));
10423  TUserGraphicVector::iterator UserGraphicPtr;
10424 
10425  UserGraphicFoundFlag = false;
10426  if(!UserGraphicVector.empty())
10427  {
10428  int x = UserGraphicVector.size();
10429  for(UserGraphicPtr = (UserGraphicVector.end() - 1); UserGraphicPtr >= UserGraphicVector.begin(); UserGraphicPtr--)
10430  {
10431  x--;
10432  if((HPosInput >= (*UserGraphicPtr).HPos) && (HPosInput < ((*UserGraphicPtr).HPos + (*UserGraphicPtr).Width)) && (VPosInput >=
10433  (*UserGraphicPtr).VPos) && (VPosInput < ((*UserGraphicPtr).VPos + (*UserGraphicPtr).Height)))
10434  {
10435  UserGraphicItem = x;
10436  UserGraphicMoveHPos = (*UserGraphicPtr).HPos;
10437  UserGraphicMoveVPos = (*UserGraphicPtr).VPos;
10438  UserGraphicFoundFlag = true;
10439  Utilities->CallLogPop(2177);
10440  return;
10441  } // if ....
10442 
10443  } // for UserGraphicPtr...
10444  } // if !UserGraphicVector...
10445 
10446  Utilities->CallLogPop(2197);
10447 }
10448 
10449 // ---------------------------------------------------------------------------
10450 
10452 {
10453  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RetrieveStripedNamedLocationGraphicsWhereRelevant," +
10454  TrackElement.LogTrack(11));
10455  Graphics::TBitmap *GraphicOutput = RailGraphics->bmTransparentBgnd; // default value
10456  int SpeedTag = TrackElement.SpeedTag;
10457 
10458  if(SpeedTag < 1)
10459  {
10460  throw Exception("Error - SpeedTag value " + AnsiString(SpeedTag) + " in RetrieveStripedNamedLocationGraphicsWhereRelevant");
10461  }
10462  switch(SpeedTag)
10463  {
10464  case 76: // t platform
10465  GraphicOutput = RailGraphics->gl76Striped;
10466  break;
10467 
10468  case 77: // h platform
10469  GraphicOutput = RailGraphics->bm77Striped;
10470  break;
10471 
10472  case 78: // v platform
10473  GraphicOutput = RailGraphics->bm78Striped;
10474  break;
10475 
10476  case 79: // r platform
10477  GraphicOutput = RailGraphics->gl79Striped;
10478  break;
10479 
10480  case 96: // concourse
10481  GraphicOutput = RailGraphics->ConcourseStriped;
10482  break;
10483 
10484  case 129: // v footbridge
10485  GraphicOutput = RailGraphics->gl129Striped;
10486  break;
10487 
10488  case 130: // h footbridge
10489  GraphicOutput = RailGraphics->gl130Striped;
10490  break;
10491 
10492  case 131: // non-station named loc
10493  GraphicOutput = RailGraphics->bmNameStriped;
10494  break;
10495 
10496  case 145: // v u'pass
10497  GraphicOutput = RailGraphics->gl145Striped;
10498  break;
10499 
10500  case 146: // h u'pass
10501  GraphicOutput = RailGraphics->gl146Striped;
10502  break;
10503 
10504  default:
10505  GraphicOutput = TrackElement.GraphicPtr;
10506  break;
10507  }
10508  Utilities->CallLogPop(642);
10509  return(GraphicOutput);
10510 }
10511 
10512 // ---------------------------------------------------------------------------
10513 
10515 {
10516  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackElementAt," + AnsiString(At));
10517  if((At < 0) || ((unsigned int)At >= TrackVector.size()))
10518  {
10519 // Utilities->CallLogPop(2281); this shouldn't be here, introduced 02/06/21 at revision 3745fadb... with no explanation
10520  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in TrackElementAt");
10521  }
10522  Utilities->CallLogPop(643);
10523  return(TrackVector.at(At));
10524 }
10525 
10526 // ---------------------------------------------------------------------------
10527 
10529 {
10530  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveTrackElementAt," + AnsiString(At));
10531  if((At < 0) || ((unsigned int)At >= InactiveTrackVector.size()))
10532  {
10533  throw Exception("Out of Range Error, vector size: " + AnsiString(InactiveTrackVector.size()) + ", At: " + AnsiString(At) +
10534  " in InactiveTrackElementAt");
10535  }
10536  Utilities->CallLogPop(644);
10537  return(InactiveTrackVector.at(At));
10538 }
10539 
10540 // ---------------------------------------------------------------------------
10541 
10542 bool TTrack::BlankElementAt(int Caller, int At) const
10543 {
10544  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BlankElementAt," + AnsiString(At));
10545  if((At < 0) || ((unsigned int)At >= TrackVector.size()))
10546  {
10547  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in BlankElementAt");
10548  }
10549  if(TrackVector.at(At).SpeedTag == 0) //have to use TrackVector.at because TrackElementAt is non-const
10550  {
10551  Utilities->CallLogPop(645);
10552  return(true);
10553  }
10554  else
10555  {
10556  Utilities->CallLogPop(646);
10557  return(false);
10558  }
10559 }
10560 
10561 // ---------------------------------------------------------------------------
10562 
10563 bool TTrack::OneNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName)
10564 /* Check sufficient elements with same ActiveTrackElementName linked together without any trailing point links to allow a train split.
10565  Only one length is needed to return true, but this doesn't mean that all platforms at the location are long enough. When a
10566  split is required a specific check is made using ThisNamedLocationLongEnoughForSplit.
10567  Need at least two linked ActiveTrackElementNames, with connected elements at each end, which may or may not be ActiveTrackElementNames,
10568  and no connections via point trailing links. Note that these conditions exclude opposed buffers since these not linked.
10569 */
10570 {
10571  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneNamedLocationLongEnoughForSplit," + LocationName);
10572  TTrackElement InactiveElement, FirstNamedElement, SecondNamedElement, FirstNamedLinkedElement, SecondNamedLinkedElement;
10573  int FirstNamedExitPos, SecondNamedExitPos, FirstNamedLinkedExitPos, SecondNamedLinkedEntryPos;
10574  TLocationNameMultiMapIterator SNIterator;
10575  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
10576 
10577  if(SNRange.first == SNRange.second)
10578  {
10579  Utilities->CallLogPop(972);
10580  return(false); // should have been caught earlier but include for completeness
10581  }
10582  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
10583  {
10584  if(SNIterator->second < 0)
10585  {
10586  continue; // exclude footcrossings
10587  }
10588  InactiveElement = InactiveTrackElementAt(47, SNIterator->second);
10589  if(InactiveElement.TrackType == Concourse)
10590  {
10591  continue; // only interested in locations where ActiveTrackElementName may be set (not needed at v2.10.0 but leave in)
10592  }
10593  if(!TrackElementPresentAtHV(1, InactiveElement.HLoc, InactiveElement.VLoc)) //added at v2.10.0 in response to Jason Bassett error notified 14/08/21
10594  {
10595  continue; // only interested in locations where ActiveTrackElementName may be set
10596  }
10597  THVPair HVPair;
10598  HVPair.first = InactiveElement.HLoc;
10599  HVPair.second = InactiveElement.VLoc;
10600  if(TrackMap.find(HVPair) == TrackMap.end())
10601  {
10602  throw Exception
10603  ("Error - failed to find element in TrackMap for a non-concourse element in LocationNameMultiMap in OneNamedLocationLongEnoughForSplit (1)");
10604  }
10605  int TVPos = TrackMap.find(HVPair)->second;
10606  FirstNamedElement = TrackElementAt(560, TVPos);
10607  // first check linked on both sides, skip the check if not
10608  if((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1))
10609  {
10610  continue;
10611  }
10612  // check if another ActiveTrackElementName connected via link pos 0 (can only be 0 or 1 since the only 2-track elements that can be
10613  // ActiveTrackElementNames are points and excluding trailing connections for points
10614  FirstNamedExitPos = 0;
10615  {
10616  SecondNamedElement = TrackElementAt(561, FirstNamedElement.Conn[FirstNamedExitPos]);
10617  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
10618  FirstNamedLinkedElement = TrackElementAt(562, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
10619  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
10620  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
10621  {
10622  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
10623  {
10624  SecondNamedLinkedElement = TrackElementAt(563, SecondNamedElement.Conn[SecondNamedExitPos]);
10625  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
10626  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
10627  // success, now check FirstNamedElement link not trailing points & if so all OK
10628  {
10629  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
10630  {
10631  Utilities->CallLogPop(1002);
10632  return(true);
10633  }
10634  }
10635  }
10636  }
10637  }
10638  // failed, try link 1
10639  FirstNamedExitPos = 1;
10640  {
10641  SecondNamedElement = TrackElementAt(564, FirstNamedElement.Conn[FirstNamedExitPos]);
10642  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
10643  FirstNamedLinkedElement = TrackElementAt(565, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
10644  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
10645  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
10646  {
10647  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
10648  {
10649  SecondNamedLinkedElement = TrackElementAt(566, SecondNamedElement.Conn[SecondNamedExitPos]);
10650  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
10651  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
10652  // success, now check FirstNamedElement link not trailing points & if so all OK
10653  {
10654  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
10655  {
10656  Utilities->CallLogPop(1003);
10657  return(true);
10658  }
10659  }
10660  }
10661  }
10662  }
10663  }
10664  Utilities->CallLogPop(1004);
10665  return(false);
10666 }
10667 
10668 // ---------------------------------------------------------------------------
10669 bool TTrack::ThisNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName, int FirstNamedElementPos, int &SecondNamedElementPos,
10670  int &FirstNamedLinkedElementPos, int &SecondNamedLinkedElementPos)
10671 // for success need two linked named location elements, so that one element of each train can be at the location
10672 // FirstNamedElementPos is the input vector position and the first (if successful) of the two linked named location elements,
10673 // the second is SecondNamedElementPos, and the two linked elements are FirstNamedLinkedElementPos and SecondNamedLinkedElementPos.
10674 // the two trains will occupy these 4 elements
10675 // All are track vector positions, all but the input being references and set within the function.
10676 {
10677 /* Check sufficient elements (including TrackvectorPosition) with same ActiveTrackElementName linked together without any trailing point
10678  links and including the element FirstNamedElementPos to allow a train split. Need at least two linked ActiveTrackElementNames, with
10679  connected elements at each end, which may or may not be ActiveTrackElementNames, and no connections via point trailing links. Note that
10680  these conditions exclude opposed buffers since these not linked. Return the two train positions and exit positions for use in train
10681  splitting.
10682 */
10683  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ThisNamedLocationLongEnoughForSplit," + LocationName +
10684  AnsiString(FirstNamedElementPos));
10685  TTrackElement InactiveElement, FirstNamedElement, SecondNamedElement, FirstNamedLinkedElement, SecondNamedLinkedElement;
10686  int FirstNamedExitPos, SecondNamedExitPos, FirstNamedLinkedExitPos, SecondNamedLinkedEntryPos;
10687 
10688  SecondNamedElementPos = -1;
10689  FirstNamedLinkedElementPos = -1;
10690  SecondNamedLinkedElementPos = -1;
10691  TLocationNameMultiMapIterator SNIterator;
10692  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
10693 
10694  if(SNRange.first == SNRange.second) // i.e. location name not in map
10695  {
10696  Utilities->CallLogPop(1005);
10697  return(false); // should have been caught earlier but include for completeness
10698  }
10699  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
10700  {
10701  if(SNIterator->second < 0)
10702  {
10703  continue; // exclude footcrossings
10704  }
10705  InactiveElement = InactiveTrackElementAt(69, SNIterator->second);
10706  if(InactiveElement.TrackType == Concourse)
10707  {
10708  continue; // only interested in locations where ActiveTrackElementName may be set
10709  }
10710  THVPair HVPair;
10711  HVPair.first = InactiveElement.HLoc;
10712  HVPair.second = InactiveElement.VLoc;
10713  if(TrackMap.find(HVPair) == TrackMap.end())
10714  {
10715  if(InactiveElement.TrackType == NamedNonStationLocation) // added at v2.2.0 to correct the error Xeon reported on 14/07/18.
10716  // If there is a NamedNonStationLocation without an associated active track element (effectively a non-station concourse)
10717  // then it won't be found in TrackMap but it's still legitimate.
10718  {
10719  continue;
10720  }
10721  else // for anything else throw the error
10722  {
10723  throw Exception
10724  ("Error - failed to find element in TrackMap for a non-concourse element in LocationNameMultiMap in ThisNamedLocationLongEnoughForSplit (2)"
10725  );
10726  }
10727  }
10728  int TVPos = TrackMap.find(HVPair)->second;
10729  if(TVPos != FirstNamedElementPos)
10730  {
10731  continue; // looking for an exact match
10732  }
10733  FirstNamedElement = TrackElementAt(567, TVPos);
10734  // first check linked on both sides, skip the check if not
10735  if((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1))
10736  {
10737  continue;
10738  }
10739  // check if another ActiveTrackElementName connected via link pos 0 (can only be 0 or 1 since the only 2-track elements that can be
10740  // ActiveTrackElementNames are points and excluding trailing connections for points
10741  FirstNamedExitPos = 0;
10742  {
10743  SecondNamedElement = TrackElementAt(568, FirstNamedElement.Conn[FirstNamedExitPos]);
10744  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
10745  FirstNamedLinkedElement = TrackElementAt(569, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
10746  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
10747  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
10748  {
10749  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
10750  {
10751  SecondNamedLinkedElement = TrackElementAt(570, SecondNamedElement.Conn[SecondNamedExitPos]);
10752  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
10753  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
10754  // success, now check FirstNamedElement link not trailing points & if so all OK
10755  {
10756  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
10757  {
10758  SecondNamedElementPos = FirstNamedElement.Conn[FirstNamedExitPos];
10759  FirstNamedLinkedElementPos = FirstNamedElement.Conn[1 - FirstNamedExitPos];
10760  SecondNamedLinkedElementPos = SecondNamedElement.Conn[SecondNamedExitPos];
10761  Utilities->CallLogPop(1006);
10762  return(true);
10763  }
10764  }
10765  }
10766  }
10767  }
10768  // failed, try link 1
10769  FirstNamedExitPos = 1;
10770  {
10771  SecondNamedElement = TrackElementAt(571, FirstNamedElement.Conn[FirstNamedExitPos]);
10772  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
10773  FirstNamedLinkedElement = TrackElementAt(572, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
10774  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
10775  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
10776  {
10777  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
10778  {
10779  SecondNamedLinkedElement = TrackElementAt(573, SecondNamedElement.Conn[SecondNamedExitPos]);
10780  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
10781  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
10782  // success, now check FirstNamedElement link not trailing points & if so all OK
10783  {
10784  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
10785  {
10786  SecondNamedElementPos = FirstNamedElement.Conn[FirstNamedExitPos];
10787  FirstNamedLinkedElementPos = FirstNamedElement.Conn[1 - FirstNamedExitPos];
10788  SecondNamedLinkedElementPos = SecondNamedElement.Conn[SecondNamedExitPos];
10789  Utilities->CallLogPop(1007);
10790  return(true);
10791  }
10792  }
10793  }
10794  }
10795  }
10796  }
10797  Utilities->CallLogPop(1008);
10798  return(false);
10799 }
10800 
10801 // ---------------------------------------------------------------------------
10802 
10803 bool TTrack::OneNamedLocationElementAtLocation(int Caller, AnsiString LocationName)
10804 {
10805  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneNamedLocationElementAtLocation," + LocationName);
10806  TLocationNameMultiMapIterator SNIterator;
10807  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
10808 
10809  if(SNRange.first != SNRange.second)
10810  {
10811  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
10812  {
10813  if(SNIterator->second < 0)
10814  {
10815  continue; // only looking for inactive (platform or NamedNonStationLocation) elements
10816  }
10817  if((InactiveTrackElementAt(33, SNIterator->second).TrackType == Platform) || (InactiveTrackElementAt(81,
10818  SNIterator->second).TrackType == NamedNonStationLocation))
10819  {
10820  Utilities->CallLogPop(1121);
10821  return(true);
10822  }
10823  }
10824  }
10825  Utilities->CallLogPop(848);
10826  return(false);
10827 }
10828 
10829 // ---------------------------------------------------------------------------
10830 
10831 bool TTrack::PlatformOnSignalSide(int Caller, int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap* &SignalPlatformGraphic)
10832 {
10833 // dropped special platforms at v0.6 as didn't show well against ground signals & not needed anyway as plats always plotted first where there are signals
10834  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlatformOnSignalSide," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
10835  "," + AnsiString(SpeedTag));
10836  if(!IsPlatformOrNamedNonStationLocationPresent(5, HLoc, VLoc)) // can't be a named location so no ambiguity
10837  {
10838  Utilities->CallLogPop(949);
10839  return(false);
10840  }
10841  bool FoundFlag;
10842  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(27, HLoc, VLoc, FoundFlag);
10843 
10844  if(!FoundFlag)
10845  {
10846  throw Exception("Error, FoundFlag false in PlatformOnSignalSide after IsPlatformOrNamedNonStationLocationPresent called successfully");
10847  }
10848  TTrackElement IAElement;
10849 
10850  if(SpeedTag == 68) // top sig
10851  {
10852  if((InactiveTrackElementAt(22, IMPair.first).SpeedTag == 76) || (InactiveTrackElementAt(23, IMPair.second).SpeedTag == 76)) // top plat
10853  {
10854  if(InactiveTrackElementAt(49, IMPair.first).SpeedTag == 76)
10855  {
10856  IAElement = InactiveTrackElementAt(50, IMPair.first);
10857  }
10858  else
10859  {
10860  IAElement = InactiveTrackElementAt(51, IMPair.second);
10861  }
10862  if(IAElement.LocationName == "")
10863  {
10864 // SignalPlatformGraphic = RailGraphics->Plat68Striped;
10865  SignalPlatformGraphic = RailGraphics->gl76Striped;
10866  }
10867  else
10868  {
10869 // SignalPlatformGraphic = RailGraphics->Plat68;
10870  SignalPlatformGraphic = RailGraphics->gl76;
10871  }
10872  Utilities->CallLogPop(950);
10873  return(true);
10874  }
10875  }
10876  else if(SpeedTag == 69) // bot sig
10877  {
10878  if((InactiveTrackElementAt(70, IMPair.first).SpeedTag == 77) || (InactiveTrackElementAt(75, IMPair.second).SpeedTag == 77)) // bot plat
10879  {
10880  if(InactiveTrackElementAt(76, IMPair.first).SpeedTag == 77)
10881  {
10882  IAElement = InactiveTrackElementAt(77, IMPair.first);
10883  }
10884  else
10885  {
10886  IAElement = InactiveTrackElementAt(78, IMPair.second);
10887  }
10888  if(IAElement.LocationName == "")
10889  {
10890 // SignalPlatformGraphic = RailGraphics->Plat69Striped;
10891  SignalPlatformGraphic = RailGraphics->bm77Striped;
10892  }
10893  else
10894  {
10895 // SignalPlatformGraphic = RailGraphics->Plat69;
10896  SignalPlatformGraphic = RailGraphics->bm77;
10897  }
10898  Utilities->CallLogPop(951);
10899  return(true);
10900  }
10901  }
10902  else if(SpeedTag == 70) // left sig
10903  {
10904  if((InactiveTrackElementAt(52, IMPair.first).SpeedTag == 78) || (InactiveTrackElementAt(79, IMPair.second).SpeedTag == 78)) // left plat
10905  {
10906  if(InactiveTrackElementAt(80, IMPair.first).SpeedTag == 78)
10907  {
10908  IAElement = InactiveTrackElementAt(55, IMPair.first);
10909  }
10910  else
10911  {
10912  IAElement = InactiveTrackElementAt(82, IMPair.second);
10913  }
10914  if(IAElement.LocationName == "")
10915  {
10916 // SignalPlatformGraphic = RailGraphics->Plat70Striped;
10917  SignalPlatformGraphic = RailGraphics->bm78Striped;
10918  }
10919  else
10920  {
10921 // SignalPlatformGraphic = RailGraphics->Plat70;
10922  SignalPlatformGraphic = RailGraphics->bm78;
10923  }
10924  Utilities->CallLogPop(952);
10925  return(true);
10926  }
10927  }
10928  else if(SpeedTag == 71) // right sig
10929  {
10930  if((InactiveTrackElementAt(83, IMPair.first).SpeedTag == 79) || (InactiveTrackElementAt(58, IMPair.second).SpeedTag == 79)) // right plat
10931  {
10932  if(InactiveTrackElementAt(84, IMPair.first).SpeedTag == 79)
10933  {
10934  IAElement = InactiveTrackElementAt(85, IMPair.first);
10935  }
10936  else
10937  {
10938  IAElement = InactiveTrackElementAt(86, IMPair.second);
10939  }
10940  if(IAElement.LocationName == "")
10941  {
10942 // SignalPlatformGraphic = RailGraphics->Plat71Striped;
10943  SignalPlatformGraphic = RailGraphics->gl79Striped;
10944  }
10945  else
10946  {
10947 // SignalPlatformGraphic = RailGraphics->Plat71;
10948  SignalPlatformGraphic = RailGraphics->gl79;
10949  }
10950  Utilities->CallLogPop(953);
10951  return(true);
10952  }
10953  }
10954  Utilities->CallLogPop(954);
10955  return(false);
10956 }
10957 
10958 // ---------------------------------------------------------------------------
10959 
10960 bool TTrack::OtherTrainOnTrack(int Caller, int NextPos, int NextEntryPos, int OwnTrainID)
10961 // returns true if another train on NextEntryPos track of element at NextPos, whether bridge or not
10962 // false if not, if NextPos == -1, or if only own train on the track
10963 {
10964  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OtherTrainOnTrack," + AnsiString(NextPos) + "," +
10965  AnsiString(NextEntryPos) + "," + AnsiString(OwnTrainID));
10966  if(NextEntryPos < 0)
10967  {
10968  Utilities->CallLogPop(1348);
10969  return(false);
10970  }
10971  TTrackElement TrackElement = TrackElementAt(713, NextPos);
10972 
10973  if(TrackElement.TrackType != Bridge)
10974  {
10975  Utilities->CallLogPop(1349);
10976  return ((TrackElement.TrainIDOnElement > -1) && (TrackElement.TrainIDOnElement != OwnTrainID));
10977  }
10978 // bridge if reach here
10979  if(NextEntryPos > 1)
10980  {
10981  Utilities->CallLogPop(1350);
10982  return ((TrackElement.TrainIDOnBridgeTrackPos23 > -1) && (TrackElement.TrainIDOnBridgeTrackPos23 != OwnTrainID));
10983  }
10984  else
10985  {
10986  Utilities->CallLogPop(1351);
10987  return ((TrackElement.TrainIDOnBridgeTrackPos01 > -1) && (TrackElement.TrainIDOnBridgeTrackPos01 != OwnTrainID));
10988  }
10989 }
10990 
10991 // ---------------------------------------------------------------------------
10992 
10994 {
10995  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SelectVectorAt," + AnsiString(At));
10996  if((At < 0) || ((unsigned int)At >= SelectVectorSize()))
10997  {
10998  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in SelectVectorAt");
10999  }
11000  Utilities->CallLogPop(1483);
11001  return(SelectVector.at(At));
11002 }
11003 
11004 // ---------------------------------------------------------------------------
11005 
11006 bool TTrack::IsATrackElementAdjacentToLink(int Caller, int HLocIn, int VLocIn, int LinkIn)
11007 // For element at HLoc & VLoc, returns true if there is an element adjacent to LinkIn
11008 {
11009  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsATrackElementAdjacentToLink," + AnsiString(HLocIn) + "," +
11010  AnsiString(VLocIn) + "," + AnsiString(LinkIn));
11011  bool FoundFlag = false;
11012  int NewHLoc = HLocIn + LinkHVArray[LinkIn][0];
11013  int NewVLoc = VLocIn + LinkHVArray[LinkIn][1];
11014 
11015  GetVectorPositionFromTrackMap(41, NewHLoc, NewVLoc, FoundFlag);
11016  Utilities->CallLogPop(1538);
11017  return(FoundFlag);
11018 }
11019 
11020 // ---------------------------------------------------------------------------
11021 
11022 bool TTrack::FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
11023 {
11024 // return true if find an inactive element called 'Name'
11025  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindHighestAndLowestNamedElements," + Name);
11026  int VLocHi = -2000000000, VLocLo = 2000000000, HLoc = 2000000000;
11027  bool FoundFlag = false;
11028 
11029  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
11030  {
11031  if(InactiveTrackElementAt(158, x).LocationName == Name)
11032  {
11033  FoundFlag = true;
11034  int V = InactiveTrackElementAt(159, x).VLoc;
11035  int H = InactiveTrackElementAt(160, x).HLoc;
11036  if(V > VLocHi)
11037  {
11038  VLocHi = V;
11039  }
11040  if(V < VLocLo)
11041  {
11042  VLocLo = V;
11043  }
11044  if(H < HLoc)
11045  {
11046  HLoc = H;
11047  }
11048  }
11049  }
11050  if(FoundFlag)
11051  {
11052  VPosHi = 16 * VLocHi;
11053  VPosLo = 16 * VLocLo;
11054  HPos = 16 * HLoc;
11055  Utilities->CallLogPop(1562);
11056  return(true);
11057  }
11058  else
11059  {
11060  Utilities->CallLogPop(1563);
11061  return(false);
11062  }
11063 }
11064 
11065 // ---------------------------------------------------------------------------
11066 
11067 int TTrack::FindClosestLinkPosition(int Caller, int StartTVPosition, int EndTVPosition)
11068 {
11069 // return the link array position for the element at StartTVPosition that gives the closest link to the element at EndTVPosition
11070 // NB the StartTVPosition is expected to be a single track element as only positions 0 & 1 are checked
11071  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindClosestLinkPosition," + AnsiString(StartTVPosition) + "," +
11072  AnsiString(EndTVPosition));
11073  TTrackElement &StartElement = TrackElementAt(839, StartTVPosition);
11074  TTrackElement &EndElement = TrackElementAt(840, EndTVPosition);
11075 
11076 // get H & V values for the element adjacent to Link[0] & Link[1]
11077  int NewHLocLink0 = StartElement.HLoc + LinkHVArray[StartElement.Link[0]][0];
11078  int NewVLocLink0 = StartElement.VLoc + LinkHVArray[StartElement.Link[0]][1];
11079  int NewHLocLink1 = StartElement.HLoc + LinkHVArray[StartElement.Link[1]][0];
11080  int NewVLocLink1 = StartElement.VLoc + LinkHVArray[StartElement.Link[1]][1];
11081 
11082 // compute the sum of the squares of the H & V distances between EndElement and 'New' values
11083  int Link0Squares = ((EndElement.HLoc - NewHLocLink0) * (EndElement.HLoc - NewHLocLink0)) +
11084  ((EndElement.VLoc - NewVLocLink0) * (EndElement.VLoc - NewVLocLink0));
11085  int Link1Squares = ((EndElement.HLoc - NewHLocLink1) * (EndElement.HLoc - NewHLocLink1)) +
11086  ((EndElement.VLoc - NewVLocLink1) * (EndElement.VLoc - NewVLocLink1));
11087 
11088  if(Link0Squares <= Link1Squares)
11089  {
11090  Utilities->CallLogPop(1851);
11091  return(0);
11092  }
11093  else
11094  {
11095  Utilities->CallLogPop(1852);
11096  return(1);
11097  }
11098 }
11099 
11100 // ---------------------------------------------------------------------------
11101 
11102 int TTrack::GetAnyElementOppositeLinkPos(int Caller, int TrackVectorPosition, int LinkPos, bool &Derail)
11103 {
11104  // element can be points or any other type
11105  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetAnyElementOppositeLinkPos," + AnsiString(TrackVectorPosition) + "," +
11106  AnsiString(LinkPos));
11107  Derail = false;
11108  TTrackElement &TE = Track->TrackElementAt(277, TrackVectorPosition);
11109 
11110  if((TE.TrackType == Points) && (TE.Config[LinkPos] == Lead))
11111  {
11112  if(TE.Attribute == 0)
11113  {
11114  Utilities->CallLogPop(663);
11115  return(1); // Att == 0 & ExitPos == 1 represent straight
11116  }
11117  else
11118  {
11119  Utilities->CallLogPop(664);
11120  return(3); // Att == 1 & ExitPos == 3 represent diverging
11121  }
11122  }
11123  else if((TE.TrackType == Points) && (TE.Config[LinkPos] == Trail))
11124  {
11125  if((LinkPos == 1) && (TE.Attribute == 0))
11126  {
11127  Utilities->CallLogPop(665);
11128  return(0); // Att == 0 represents straight
11129  }
11130  else if(LinkPos == 1)
11131  {
11132  Derail = true;
11133  Utilities->CallLogPop(666);
11134  return(0);
11135  }
11136  else if((LinkPos == 3) && (TE.Attribute == 1))
11137  {
11138  Utilities->CallLogPop(667);
11139  return(0);
11140  }
11141  else if(LinkPos == 3)
11142  {
11143  Derail = true;
11144  Utilities->CallLogPop(668);
11145  return(0);
11146  }
11147  }
11148  else if(LinkPos == 0)
11149  {
11150  Utilities->CallLogPop(669);
11151  return(1);
11152  }
11153  else if(LinkPos == 1)
11154  {
11155  Utilities->CallLogPop(670);
11156  return(0);
11157  }
11158  else if(LinkPos == 2)
11159  {
11160  Utilities->CallLogPop(671);
11161  return(3);
11162  }
11163  else if(LinkPos == 3)
11164  {
11165  Utilities->CallLogPop(672);
11166  return(2);
11167  }
11168  throw Exception("Error, failure in GetExitPos"); // should never reach here
11169 }
11170 
11171 // ----------------------------------------------------------------------------
11172 
11174 {
11175  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PopulateLCVector");
11176  LCVector.clear();
11177  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
11178  {
11179  if(InactiveTrackElementAt(161, x).TrackType == LevelCrossing)
11180  {
11181  LCVector.push_back(x);
11182  }
11183  }
11184  Utilities->CallLogPop(1931);
11185  return;
11186 }
11187 
11188 // ---------------------------------------------------------------------------
11189 
11190 bool TTrack::TrainOnLink(int Caller, int HLoc, int VLoc, int Link, int &TrainID) // new at v1.2.0
11191 /*
11192  Call GetVectorPositionFromTrackMap to identify the track element, then check if TrainIDOnElement > -1 (if a
11193  bridge then check relevant TrainID according to the Link), and if absent return false. If present identify
11194  the train using TrainController->TrainVectorAtIdent, and check which bit on the element in question (Lead, Mid or Lag),
11195  and then check the relevant EntryPos & ExitPos for a match with Link. If find a match return true and return the TrainID.
11196 */
11197 {
11198  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrainOnLink," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
11199  AnsiString(Link));
11200  bool FoundFlag;
11201 
11202  TrainID = -1;
11203  int VecPos = GetVectorPositionFromTrackMap(47, HLoc, VLoc, FoundFlag);
11204 
11205  if(!FoundFlag)
11206  {
11207  Utilities->CallLogPop(2001);
11208  return(false);
11209  }
11210  TTrackElement TE = TrackElementAt(882, VecPos);
11211 
11212  TrainID = TE.TrainIDOnElement;
11213  if(TE.TrackType == Bridge)
11214  {
11215  if(TE.TrainIDOnElement > -1)
11216  {
11217  if((TE.Link[0] == Link) || (TE.Link[1] == Link))
11218  {
11219  TrainID = TE.TrainIDOnBridgeTrackPos01;
11220  }
11221  else if((TE.Link[2] == Link) || (TE.Link[3] == Link))
11222  {
11223  TrainID = TE.TrainIDOnBridgeTrackPos23;
11224  }
11225  else
11226  {
11227  TrainID = -1; // shouldn't ever reach here but be safe
11228  }
11229  }
11230  }
11231  if(TrainID == -1)
11232  {
11233  Utilities->CallLogPop(2002);
11234  return(false);
11235  }
11236 // now get the train
11237  TTrain Train = TrainController->TrainVectorAtIdent(38, TrainID);
11238 
11239  if(Train.LinkOccupied(0, VecPos, Link)) // checks whether any part of train occupying Link on VecPos
11240  {
11241  Utilities->CallLogPop(2003);
11242  return(true);
11243  }
11244  TrainID = -1;
11245  Utilities->CallLogPop(2004);
11246  return(false);
11247 }
11248 
11249 // ---------------------------------------------------------------------------
11250 
11251 bool TTrack::DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
11252 /* New at v1.2.0
11253  As DiagonalFouledByRouteOrTarin but checks for a train only (may or may not be a route) and returns the ID number. Enter with H & V set for the element whose diagonal
11254  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
11255  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
11256  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
11257  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
11258  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
11259  Each of these is examined in turn for each route element in the relevant position.
11260 */
11261 {
11262  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByTrain," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
11263  "," + AnsiString(DiagonalLinkNumber));
11264  TrainID = -1;
11265  TPrefDirElement TempPrefDirElement;
11266  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
11267 
11268  if(((DiagonalLinkNumber == 1) && TrainOnLink(8, HLoc - 1, VLoc, 3, TrainID)) || ((DiagonalLinkNumber == 7) && TrainOnLink(9, HLoc - 1, VLoc, 9, TrainID)))
11269  {
11270  Utilities->CallLogPop(2027);
11271  return(true);
11272  }
11273  if(((DiagonalLinkNumber == 1) && TrainOnLink(10, HLoc, VLoc - 1, 7, TrainID)) || ((DiagonalLinkNumber == 3) && TrainOnLink(11, HLoc, VLoc - 1, 9, TrainID)))
11274  {
11275  Utilities->CallLogPop(2028);
11276  return(true);
11277  }
11278  if(((DiagonalLinkNumber == 3) && TrainOnLink(12, HLoc + 1, VLoc, 1, TrainID)) || ((DiagonalLinkNumber == 9) && TrainOnLink(13, HLoc + 1, VLoc, 7, TrainID)))
11279  {
11280  Utilities->CallLogPop(2029);
11281  return(true);
11282  }
11283  if(((DiagonalLinkNumber == 7) && TrainOnLink(14, HLoc, VLoc + 1, 1, TrainID)) || ((DiagonalLinkNumber == 9) && TrainOnLink(15, HLoc, VLoc + 1, 3, TrainID)))
11284  {
11285  Utilities->CallLogPop(2030);
11286  return(true);
11287  }
11288  Utilities->CallLogPop(2031);
11289  return(false);
11290 }
11291 
11292 // ---------------------------------------------------------------------------
11293 
11294 void TTrack::SaveUserGraphics(int Caller, std::ofstream &VecFile)
11295 {
11296  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveUserGraphics");
11297  Utilities->SaveFileInt(VecFile, UserGraphicVector.size()); // number of items
11298  TUserGraphicItem UGI;
11299  AnsiString JustFileName = "";
11300 
11301  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
11302  {
11303  UGI = UserGraphicVectorAt(17, x);
11304  int LastDelim = UGI.FileName.LastDelimiter('\\');
11305  if(LastDelim == 0) // can't find it so skip this item
11306  {
11307  continue;
11308  }
11309  else
11310  {
11311  JustFileName = UGI.FileName.SubString(LastDelim + 1, UGI.FileName.Length() - LastDelim);
11312  }
11313  Utilities->SaveFileString(VecFile, JustFileName);
11314  Utilities->SaveFileInt(VecFile, UGI.HPos);
11315  Utilities->SaveFileInt(VecFile, UGI.VPos);
11316  }
11317  Utilities->CallLogPop(2178);
11318 }
11319 
11320 // ---------------------------------------------------------------------------
11321 
11322 int TTrack::NumberOfPlatforms(int Caller, AnsiString LocationName)
11323 //checks all active track elements and lists those with ActiveTrackElementName same as LocationName in NamePosVector
11324 {
11325  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NumberOfPlatforms," + LocationName);
11326  int NumPlats = 0;
11327  TTrackElement TempElement;
11328  int TempInt;
11329 
11330  typedef std::list<int> TNamePosList;
11331  TNamePosList NamePosList;
11332  typedef TNamePosList::iterator TNPLIt;
11333  TNPLIt NPLIt;
11334  typedef std::list<int> TOnePlatList;
11335  TOnePlatList OnePlatList;
11336  typedef TOnePlatList::iterator TOPLIt;
11337  TOPLIt OPLIt;
11338 
11339  NamePosList.clear();
11340  OnePlatList.clear();
11341  for(unsigned int x = 0; x < TrackVector.size(); x++)
11342  {
11343  if(TrackElementAt(988, x).ActiveTrackElementName == LocationName)
11344  {
11345  NamePosList.push_back(x);
11346  }
11347  }
11348  //NamePosList complete
11349 
11350  if(!NamePosList.empty()) //first value for the loop examination
11351  {
11352  OnePlatList.push_back(NamePosList.back());
11353  NamePosList.pop_back(); //erase from NPV as done with it here
11354  }
11355  while(!OnePlatList.empty()) //loop to examine all linked elements
11356  {
11357  TempInt = OnePlatList.front();
11358  TempElement = TrackElementAt(989, TempInt);
11359 
11360  NPLIt = find(NamePosList.begin(), NamePosList.end(), TempElement.Conn[0]);
11361  if(NPLIt != NamePosList.end() && ((TempElement.Link[0] == 2) || (TempElement.Link[0] == 4) || (TempElement.Link[0] == 6) || (TempElement.Link[0] == 8)))
11362  {
11363  OnePlatList.push_back(TempElement.Conn[0]);
11364  NamePosList.erase(NPLIt);
11365  }
11366  NPLIt = find(NamePosList.begin(), NamePosList.end(), TempElement.Conn[1]);
11367  if(NPLIt != NamePosList.end() && ((TempElement.Link[1] == 2) || (TempElement.Link[1] == 4) || (TempElement.Link[1] == 6) || (TempElement.Link[1] == 8)))
11368  {
11369  OnePlatList.push_back(TempElement.Conn[1]);
11370  NamePosList.erase(NPLIt);
11371  }
11372  //here when loaded any connecting links into OnePlatList, so can erase the front element
11373  OnePlatList.erase(OnePlatList.begin());
11374  if(OnePlatList.empty())
11375  {
11376  NumPlats++; //finished with current linked elements so can increment NumPlats
11377  if(!NamePosList.empty())
11378  {
11379  OnePlatList.push_back(NamePosList.back()); //ready for next iteration
11380  NamePosList.pop_back(); //erase from NPV as done with it there
11381  }
11382  }
11383  }
11384  Utilities->CallLogPop(2218);
11385  return(NumPlats);
11386 }
11387 
11388 // ---------------------------------------------------------------------------
11389 // UserGraphic, PrefDir & Route functions
11390 // ---------------------------------------------------------------------------
11391 
11393 {
11394  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UserGraphicVectorAt," + AnsiString(At));
11395  if((At < 0) || ((unsigned int)At >= UserGraphicVector.size()))
11396  {
11397  throw Exception("Out of Range Error, vector size: " + AnsiString(UserGraphicVector.size()) + ", At: " + AnsiString(At) + " in UserGraphicVectorAt");
11398  }
11399  Utilities->CallLogPop(2194);
11400  return(UserGraphicVector.at(At));
11401 }
11402 
11403 // ---------------------------------------------------------------------------
11404 
11405 int TOnePrefDir::LastElementNumber(int Caller) const
11406 {
11407  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LastElementNumber,");
11408  int RetVal = PrefDirVector.size() - 1;
11409 
11410  if(RetVal < 0)
11411  {
11412  throw Exception("Return value negative in call to LastElementNumber");
11413  }
11414  Utilities->CallLogPop(114);
11415  return(RetVal);
11416 }
11417 
11418 // ---------------------------------------------------------------------------
11420 {
11421  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LastElementPtr,");
11422  if(PrefDirVector.empty())
11423  {
11424  throw Exception("PrefDirVector empty in call to LastElementPtr");
11425  }
11426  TPrefDirVectorIterator RetIT = PrefDirVector.end() - 1;
11427 
11428  Utilities->CallLogPop(115);
11429  return(RetIT);
11430 }
11431 
11432 // ---------------------------------------------------------------------------
11434 {
11435  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedPrefDirElementAt," + AnsiString(At));
11436  if((At < 0) || ((unsigned int)At >= PrefDirVector.size()))
11437  {
11438  throw Exception("Out of Range Error, vector size: " + AnsiString(PrefDirVector.size()) + ", At: " + AnsiString(At) + " in GetFixedPrefDirElementAt");
11439  }
11440  Utilities->CallLogPop(116);
11441  return(PrefDirVector.at(At));
11442 }
11443 
11444 // ---------------------------------------------------------------------------
11446 {
11447  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiablePrefDirElementAt," + AnsiString(At));
11448  if((At < 0) || ((unsigned int)At >= PrefDirVector.size()))
11449  {
11450  throw Exception("Out of Range Error, vector size: " + AnsiString(PrefDirVector.size()) + ", At: " + AnsiString(At) +
11451  " in GetModifiablePrefDirElementAt");
11452  }
11453  Utilities->CallLogPop(117);
11454  return(PrefDirVector.at(At));
11455 }
11456 
11457 // ---------------------------------------------------------------------------
11459 {
11460  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedSearchElementAt," + AnsiString(At));
11461  if((At < 0) || ((unsigned int)At >= SearchVector.size()))
11462  {
11463  throw Exception("Out of Range Error, vector size: " + AnsiString(SearchVector.size()) + ", At: " + AnsiString(At) + " in GetFixedSearchElementAt");
11464  }
11465  Utilities->CallLogPop(118);
11466  return(SearchVector.at(At));
11467 }
11468 
11469 // ---------------------------------------------------------------------------
11471 {
11472  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableSearchElementAt," + AnsiString(At));
11473  if((At < 0) || ((unsigned int)At >= SearchVector.size()))
11474  {
11475  throw Exception("Out of Range Error, vector size: " + AnsiString(SearchVector.size()) + ", At: " + AnsiString(At) + " in GetModifiableSearchElementAt");
11476  }
11477  Utilities->CallLogPop(119);
11478  return(SearchVector.at(At));
11479 }
11480 
11481 // ---------------------------------------------------------------------------
11482 bool TOnePrefDir::GetPrefDirStartElement(int Caller, int HLoc, int VLoc) // Return true if OK.
11483 /*
11484  Enter with HLoc & VLoc set to selected element. Clear PrefDirVector, check if selected element
11485  is a valid track element & return false if not. Create a TPrefDirElement from the track element and
11486  set checkcount to 4 to cover the fixed values, then add to PrefDirVector. All variable values are
11487  set in later functions.
11488 */
11489 {
11490  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPrefDirStartElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
11491  ClearPrefDir();
11492  int TrackVectorPosition;
11493  TTrackElement TrackElement;
11494 
11495  if(!(Track->FindNonPlatformMatch(5, HLoc, VLoc, TrackVectorPosition, TrackElement)))
11496  {
11497  Utilities->CallLogPop(126);
11498  return(false);
11499  }
11500 /* it can be points so drop the code below - all exits are checked, no assumptions are made about the exit position of the start element
11501  if(TrackElement.TrackType == Points)
11502  {
11503  ShowMessage("Can't start on points");//because if PrefDir leads away from the leading edge
11504  //it isn't known which trailing edge is the required PrefDir - could use the straight as
11505  //default but may already be a PrefDir up to the diverging edge, then will have a mismatch,
11506  //best to prevent it to avoid problems
11507  Utilities->CallLogPop(127);
11508  return false;
11509  }
11510 */
11511  TPrefDirElement PrefDirElement(TrackElement);
11512 
11513  PrefDirElement.TrackVectorPosition = TrackVectorPosition;
11514  PrefDirElement.CheckCount = 4; // HLoc, VLoc, SpeedTag & TrackVectorPosition
11515  StorePrefDirElement(1, PrefDirElement); // enter first element
11516 // Note that ELink not set even if a buffer or continuation - these set in
11517 // ConvertPrefDirSearchVector after 2nd element added
11518 
11519  Utilities->CallLogPop(128);
11520  return(true);
11521 }
11522 
11523 // ---------------------------------------------------------------------------
11524 bool TOnePrefDir::GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
11525 
11526 /*
11527  Enter with HLoc & VLoc set to selected element. If not a track element or if PrefDirVector empty return false.
11528  Examine the last element in the PrefDirvector, if ELink not set (start element) do an immediate
11529  check for an adjacent find (i.e. find selected element), & if succeed use SearchForPrefDir with that as XLinkPos to deal
11530  with setting the PrefDir vector, & return true. Also set FinishElement if found element was a buffer or continuation,
11531  so that the calling function knows that the PrefDir is complete.
11532  If last element was the start element but no immediate find, search on each valid exit pos in turn, using
11533  SearchForPrefDir to examine all branches. If succeed set PrefDirvector & finishelement as appropriate.
11534  Otherwise (last element not start element) check if last element was a leading point (if so can't be first element)
11535  & check again for an immediate find on either XLinkPos values 1 & 3, using SearchForPrefDir &
11536  ConvertPrefDirSearchVector to set PrefDirVector. Set FinishElement appropriately.
11537  If a leading point but not an immediate find use SearchForPrefDir on the XLinkPos values 1 & 3 in turn.
11538  If it wasn't a leading point just use XLinkPos value corresponding to XLink & Search on that. If don't
11539  find the required element return false. CheckCount is used to keep track of set values to allow check later.
11540 */
11541 
11542 {
11543  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextPrefDirElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
11544  FinishElement = false;
11545  int TrackVectorPosition;
11546 
11547  TotalSearchCount = 0;
11548  TTrackElement TrackElement, TempTrackElement;
11549 
11550  if(PrefDirVector.size() == 0)
11551  {
11552  Utilities->CallLogPop(129);
11553  return(false);
11554  }
11555  if(!(Track->FindNonPlatformMatch(6, HLoc, VLoc, TrackVectorPosition, TrackElement)))
11556  {
11557  Utilities->CallLogPop(130);
11558  return(false);
11559  }
11560 // set the search limits using the last stored element in PrefDirVector as the start point
11561 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
11562 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
11563 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
11564 
11565  TPrefDirElement StartPrefDirElement = PrefDirVector.at(LastElementNumber(72));
11566 
11567  if(TrackElement.HLoc >= StartPrefDirElement.HLoc)
11568  {
11569  SearchLimitLowH = StartPrefDirElement.HLoc - 15;
11570  SearchLimitHighH = TrackElement.HLoc + 15;
11571  }
11572  else
11573  {
11574  SearchLimitLowH = TrackElement.HLoc - 15;
11575  SearchLimitHighH = StartPrefDirElement.HLoc + 15;
11576  }
11577  if(TrackElement.VLoc >= StartPrefDirElement.VLoc)
11578  {
11579  SearchLimitLowV = StartPrefDirElement.VLoc - 15;
11580  SearchLimitHighV = TrackElement.VLoc + 15;
11581  }
11582  else
11583  {
11584  SearchLimitLowV = TrackElement.VLoc - 15;
11585  SearchLimitHighV = StartPrefDirElement.VLoc + 15;
11586  }
11587 /* dropped this for v0.4d - prevents ability to set paths for gaps that are widely separated, ok without it as search limited by SearchVector size
11588  check & TotalSearchCounts check
11589  if((abs(TrackElement.HLoc - StartPrefDirElement.HLoc) > 120) || (abs(TrackElement.VLoc - StartPrefDirElement.VLoc) > 120))
11590  {
11591  ShowMessage("Unable to reach the selected element - too far ahead");
11592  Utilities->CallLogPop(1692);
11593  return false;
11594  }
11595 */
11596 // get last PrefDir element
11597  if(PrefDirVector.at(LastElementNumber(0)).ELink == -1) // start element
11598  {
11599  // check if TrackElement adjacent to any of the 4 XLinkPos'
11600  for(int x = 0; x < 4; x++)
11601  {
11602  if(PrefDirVector.at(LastElementNumber(1)).Conn[x] == TrackVectorPosition)
11603  {
11604  PrefDirVector.at(LastElementNumber(2)).XLinkPos = x;
11605  PrefDirVector.at(LastElementNumber(3)).XLink = PrefDirVector.at(LastElementNumber(4)).Link[x];
11606  PrefDirVector.at(LastElementNumber(5)).CheckCount++;
11607  PrefDirVector.at(LastElementNumber(6)).CheckCount++;
11608  break; // can have 2 connections if have 2 adjacent gaps connected to each other but ELink & XLink
11609  // then ambiguous. Have to opt for just one, and if user wanted the other then that's unfortunate,
11610  // shouldn't ever get it in a serious railway though.
11611 // Note: ELink & ELinkPos are set in ConvertPrefDirSearchVector for the start element
11612  }
11613  }
11614  if(PrefDirVector.at(LastElementNumber(7)).XLinkPos > -1) // i.e required position must be adjacent to the start element
11615  {
11616  TempTrackElement = PrefDirVector.at(LastElementNumber(8));
11617  SearchVector.clear(); // use this & convert to set all PrefDir element values
11618  if(SearchForPrefDir(1, TempTrackElement, PrefDirVector.at(LastElementNumber(9)).XLinkPos, TrackVectorPosition))
11619  {
11621  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11622  {
11623  FinishElement = true;
11624  }
11625  Utilities->CallLogPop(131);
11626  return(true);
11627  }
11628  } // not an adjacent element
11629 
11630  // now check each of the 4 possible XLinkPos values
11631  for(int x = 0; x < 4; x++)
11632  {
11633  if((PrefDirVector.at(LastElementNumber(10)).Link[x] > 0) && (PrefDirVector.at(LastElementNumber(11)).Config[x] != End)) // i.e have somewhere to go
11634  {
11635  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find the required position
11636  TempTrackElement = PrefDirVector.at(LastElementNumber(12));
11637  SearchVector.clear();
11638  if(SearchForPrefDir(2, TempTrackElement, x, TrackVectorPosition))
11639  {
11641  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11642  {
11643  FinishElement = true;
11644  }
11645  Utilities->CallLogPop(132);
11646  return(true);
11647  }
11648  }
11649  } // here if checked all possible exits without success
11650  ShowMessage(
11651  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
11652  Utilities->CallLogPop(133);
11653  return(false);
11654  }
11655 // dealt above with LastPrefDirElement being the start element (which can be points)
11656 
11657  if((PrefDirVector.at(LastElementNumber(13)).TrackType == Points) && (PrefDirVector.at(LastElementNumber(14)).Config[PrefDirVector.at(LastElementNumber(15))
11658  .ELinkPos] == Lead)) // leading point
11659  {
11660  if(PrefDirVector.at(LastElementNumber(16)).Conn[1] == TrackVectorPosition) // found it next to XLinkPos = 1
11661  {
11662  PrefDirVector.at(LastElementNumber(17)).XLinkPos = 1;
11663  PrefDirVector.at(LastElementNumber(18)).XLink = PrefDirVector.at(LastElementNumber(19)).Link[1];
11664  // can't be buffers or gap if points
11665  PrefDirVector.at(LastElementNumber(20)).CheckCount++;
11666  PrefDirVector.at(LastElementNumber(21)).CheckCount++;
11667  TempTrackElement = PrefDirVector.at(LastElementNumber(22));
11668  SearchVector.clear();
11669  if(SearchForPrefDir(3, TempTrackElement, 1, TrackVectorPosition)) // bound to return true
11670  {
11672  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11673  {
11674  FinishElement = true;
11675  }
11676  Utilities->CallLogPop(134);
11677  return(true);
11678  }
11679  }
11680  if(PrefDirVector.at(LastElementNumber(23)).Conn[3] == TrackVectorPosition) // found it next to XLinkPos = 3
11681  {
11682  PrefDirVector.at(LastElementNumber(24)).XLinkPos = 3;
11683  PrefDirVector.at(LastElementNumber(25)).XLink = PrefDirVector.at(LastElementNumber(26)).Link[3];
11684  PrefDirVector.at(LastElementNumber(27)).CheckCount++;
11685  PrefDirVector.at(LastElementNumber(28)).CheckCount++;
11686  TempTrackElement = PrefDirVector.at(LastElementNumber(29));
11687  SearchVector.clear();
11688  if(SearchForPrefDir(4, TempTrackElement, 3, TrackVectorPosition)) // bound to return true
11689  {
11691  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11692  {
11693  FinishElement = true;
11694  }
11695  Utilities->CallLogPop(135);
11696  return(true);
11697  }
11698  }
11699 // above dealt with immediate finds for leading point,
11700 // now deal with ordinary searches for leading point
11701  PrefDirVector.at(LastElementNumber(30)).XLinkPos = 1;
11702  PrefDirVector.at(LastElementNumber(31)).XLink = PrefDirVector.at(LastElementNumber(32)).Link[1];
11703  PrefDirVector.at(LastElementNumber(33)).CheckCount++;
11704  PrefDirVector.at(LastElementNumber(34)).CheckCount++;
11705  TempTrackElement = PrefDirVector.at(LastElementNumber(35));
11706  SearchVector.clear();
11707  if(SearchForPrefDir(5, TempTrackElement, 1, TrackVectorPosition))
11708  {
11710  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11711  {
11712  FinishElement = true;
11713  }
11714  Utilities->CallLogPop(136);
11715  return(true);
11716  }
11717  PrefDirVector.at(LastElementNumber(36)).XLinkPos = 3;
11718  PrefDirVector.at(LastElementNumber(37)).XLink = PrefDirVector.at(LastElementNumber(38)).Link[3];
11719  // note that CheckCount already increased to allow for XLinkPos & XLink
11720  TempTrackElement = PrefDirVector.at(LastElementNumber(39));
11721  SearchVector.clear();
11722  if(SearchForPrefDir(6, TempTrackElement, 3, TrackVectorPosition))
11723  {
11725  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11726  {
11727  FinishElement = true;
11728  }
11729  Utilities->CallLogPop(137);
11730  return(true);
11731  }
11732 // here if failed to find match for leading point
11733  PrefDirVector.at(LastElementNumber(69)).CheckCount--; // to removed the earlier increments for XLinkPos & XLink
11734  PrefDirVector.at(LastElementNumber(70)).CheckCount--;
11735  ShowMessage(
11736  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
11737  Utilities->CallLogPop(138);
11738  return(false);
11739  }
11740 // leading point fully dealt with above
11741 // here with an ordinary element, just do an ordinary search - no need to search for an immediate find
11742 // separately as covered in ordinary search.
11743 
11744  TempTrackElement = PrefDirVector.at(LastElementNumber(40));
11745  SearchVector.clear();
11746 // no need to check for valid XLinkPos as not start element and not end element or would not reach here
11747  if(SearchForPrefDir(7, TempTrackElement, PrefDirVector.at(LastElementNumber(41)).XLinkPos, TrackVectorPosition))
11748  {
11750  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11751  {
11752  FinishElement = true;
11753  }
11754  Utilities->CallLogPop(139);
11755  return(true);
11756  }
11757  ShowMessage(
11758  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
11759  Utilities->CallLogPop(140);
11760  return(false); // failed to find required element
11761 }
11762 
11763 // ---------------------------------------------------------------------------
11764 
11765 bool TOnePrefDir::SearchForPrefDir(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition)
11766 /*
11767  Enter with CurrentTrackElement stored in the PrefDirVector, XLinkPos set to the link
11768  to search on, & SearchVector cleared unless entered recursively. Function is a continuous loop that
11769  exits when find required element (returns true) or reaches a buffer or continuation or otherwise fails a search condition (returns false).
11770  Keep a count of entries in SearchVector during the current function call, so that this number can be
11771  erased for an unproductive branch search.
11772  Create a NextTrackElement from Current & XLinkPos as far as possible, & check if found required
11773  element. If so save it & return true. If not check if buffer, continuation, or earlier position
11774  in SearchVector or PrefDirVector, & if so erase all searchvector & return false. If OK check if a leading point and
11775  if so do up to 2 recursive searches for the 2 exits. If fail on both erase searchvector & return false.
11776  If not any of above, store element in searchvector, set the new current element values from the
11777  SearchElement, then go back to the while loop for the next step in the search.
11778 */
11779 {
11780  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForPrefDir," + CurrentTrackElement.LogTrack(13) + "," +
11781  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition));
11782  int VectorCount = 0;
11783 
11784  while(true)
11785  {
11786  if(CurrentTrackElement.Config[XLinkPos] == End) // buffers or continuation
11787  {
11788  for(int x = 0; x < VectorCount; x++)
11789  {
11790  SearchVector.erase(SearchVector.end() - 1);
11791  }
11792  Utilities->CallLogPop(141);
11793  return(false);
11794  }
11795  int NextPosition = CurrentTrackElement.Conn[XLinkPos];
11796  TTrackElement NextTrackElement = Track->TrackElementAt(74, NextPosition);
11797  TPrefDirElement SearchElement(NextTrackElement);
11798  SearchElement.TrackVectorPosition = NextPosition;
11799  int NextELinkPos = CurrentTrackElement.ConnLinkPos[XLinkPos];
11800  SearchElement.ELinkPos = NextELinkPos;
11801  SearchElement.ELink = SearchElement.Link[SearchElement.ELinkPos];
11802  int NextXLinkPos;
11803  if(SearchElement.ELinkPos == 0)
11804  {
11805  NextXLinkPos = 1;
11806  }
11807  if(SearchElement.ELinkPos == 1)
11808  {
11809  NextXLinkPos = 0;
11810  }
11811  if(SearchElement.ELinkPos == 2)
11812  {
11813  NextXLinkPos = 3;
11814  }
11815  if(SearchElement.ELinkPos == 3)
11816  {
11817  NextXLinkPos = 2;
11818  }
11819  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
11820  {
11821  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
11822  // but may be buffers, continuation or gap
11823  SearchElement.XLinkPos = NextXLinkPos;
11824  }
11825 // can't set XLink or XLinkPos yet if the element is a leading point.
11826 // check if found it
11827  if(SearchElement.TrackVectorPosition == RequiredPosition)
11828  {
11829  SearchVector.push_back(SearchElement); // XLink & XLinkPos won't be set if a leading point
11830  VectorCount++; // not really needed but include for tidyness
11831  TotalSearchCount++;
11832  Utilities->CallLogPop(142);
11833  return(true);
11834  }
11835 // check if PrefDirVector > 200 and if so reject further searches (to avoid possible problems in converting
11836 // very long vectors) - warning given in ConvertPrefDirSearchVector, though can still add elements one
11837 // at a time - drop this
11838 /*
11839  if(PrefDirVector.size() > 200)
11840  {
11841  for(int x=0;x<VectorCount;x++) SearchVector.erase(SearchVector.end() - 1);
11842  Utilities->CallLogPop(1419);
11843  return false;
11844  }
11845 */
11846 // check if a buffer or continuation
11847  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
11848  {
11849  for(int x = 0; x < VectorCount; x++)
11850  {
11851  SearchVector.erase(SearchVector.end() - 1);
11852  }
11853  Utilities->CallLogPop(143);
11854  return(false);
11855  }
11856 // check if reached an earlier position on search PrefDir with same entry value
11857  for(unsigned int x = 0; x < SearchVector.size(); x++)
11858  {
11859  if((SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition) && (SearchElement.ELink == SearchVector.at(x).ELink))
11860  {
11861  for(int x = 0; x < VectorCount; x++)
11862  {
11863  SearchVector.erase(SearchVector.end() - 1);
11864  }
11865  Utilities->CallLogPop(144);
11866  return(false);
11867  }
11868  }
11869 // check if reached an earlier position in the PrefDirVector with same entry value (without this can keep adding entries
11870 // to PrefDir4MultiMap, and since only 4 are searched an error can occur)
11871  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
11872  {
11873  if((SearchElement.TrackVectorPosition == PrefDirVector.at(x).TrackVectorPosition) && (SearchElement.ELink == PrefDirVector.at(x).ELink))
11874  {
11875  for(int x = 0; x < VectorCount; x++)
11876  {
11877  SearchVector.erase(SearchVector.end() - 1);
11878  }
11879  Utilities->CallLogPop(1417);
11880  return(false);
11881  }
11882  }
11883 
11884 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
11885 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
11886 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
11888  {
11889  for(int x = 0; x < VectorCount; x++)
11890  {
11891  SearchVector.erase(SearchVector.end() - 1);
11892  }
11893  Utilities->CallLogPop(1691);
11894  return(false);
11895  }
11896 // check if SearchVector reached 150, and if so reject, to save time in searching for PrefDirs
11897  if(SearchVector.size() > 150)
11898  {
11899  for(int x = 0; x < VectorCount; x++)
11900  {
11901  SearchVector.erase(SearchVector.end() - 1);
11902  }
11903  Utilities->CallLogPop(1418);
11904  return(false);
11905  }
11906 // check if reached a leading point
11907  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead))
11908  {
11909 // push element with XLink set to position [1]
11910  SearchElement.XLink = SearchElement.Link[1];
11911  SearchElement.XLinkPos = 1;
11912  SearchVector.push_back(SearchElement);
11913  VectorCount++;
11914  TotalSearchCount++;
11915  // recursive search at XLinkPos of 1 (i.e. 1st trailing exit)
11916  // Note that have to use a TTrackElement in the recursive search, so SearchElement
11917  // can't be used. NextTrackElement is the corresponding TTrackElement.
11918  if(SearchForPrefDir(8, NextTrackElement, 1, RequiredPosition))
11919  {
11920  Utilities->CallLogPop(145);
11921  return(true);
11922  }
11923  else
11924  {
11925 // remove leading point with XLinkPos [1]
11926  SearchVector.erase(SearchVector.end() - 1);
11927  VectorCount--;
11928 // push element with XLink set to position [3]
11929  SearchElement.XLink = SearchElement.Link[3];
11930  SearchElement.XLinkPos = 3;
11931  SearchVector.push_back(SearchElement);
11932  VectorCount++;
11933  TotalSearchCount++;
11934 // recursive search at XLinkPos of 3 (i.e. 2nd trailing exit)
11935  if(SearchForPrefDir(9, NextTrackElement, 3, RequiredPosition))
11936  {
11937  Utilities->CallLogPop(146);
11938  return(true);
11939  }
11940  else
11941  {
11942  for(int x = 0; x < VectorCount; x++)
11943  {
11944  SearchVector.erase(SearchVector.end() - 1);
11945  }
11946  Utilities->CallLogPop(147);
11947  return(false);
11948  }
11949  }
11950  } // if leading point
11951 
11952 // here if ordinary element, push it, inc vector & update CurrentTrackElement
11953 // ready for next element on PrefDir
11954  SearchVector.push_back(SearchElement);
11955  VectorCount++;
11956  TotalSearchCount++;
11957  XLinkPos = NextXLinkPos;
11958  CurrentTrackElement = SearchElement;
11959  } // while(true)
11960 }
11961 
11962 // ---------------------------------------------------------------------------
11963 
11965 /*
11966  Enter with SearchVector established. This contains ELink + Pos, XLink + Pos, & TrackVectorPosition
11967  for each element on the search PrefDir, though if the last element is a leading point
11968  then the final XLink won't be set.
11969  Note also that the last element in the PrefDirVector (as opposed to the searchvector) may not have its ELink set (if it was the start)
11970  nor its XLink set (if it was the start or a leading point), so these are checked first and together with EXNumber set as necessary.
11971  The remaining PrefDirVector elements are then set from the searchvector & checkcount keeps pace as values are added.
11972 */
11973 {
11974  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertPrefDirSearchVector");
11975  if(SearchVector.size() == 0)
11976  {
11977  throw Exception("Error, SearchVector empty");
11978  }
11979 // get first SearchElement in order to set last PrefDirelement
11980  TPrefDirElement SearchElement = SearchVector.at(0);
11981 
11982 // set last PrefDir element XLink & ELink values if not already set
11983 // ELink & XLink not set if was first element in PrefDir; XLink also not set if was a leading point
11984  for(int x = 0; x < 4; x++)
11985  {
11986  if(PrefDirVector.at(LastElementNumber(42)).Conn[x] == SearchElement.TrackVectorPosition)
11987  {
11988  if(PrefDirVector.at(LastElementNumber(43)).XLink == -1) // i.e. not set
11989  {
11990  PrefDirVector.at(LastElementNumber(44)).XLink = PrefDirVector.at(LastElementNumber(45)).Link[x];
11991  PrefDirVector.at(LastElementNumber(46)).XLinkPos = x;
11992  PrefDirVector.at(LastElementNumber(47)).CheckCount++;
11993  PrefDirVector.at(LastElementNumber(48)).CheckCount++;
11994  }
11995  int ELinkPos;
11996  if(PrefDirVector.at(LastElementNumber(49)).XLinkPos == 0)
11997  {
11998  ELinkPos = 1; // use actual value rather than 'x' as may be a gap
11999  }
12000  // with both ends linked to 1st searchvector element, & if XLink was set then x may not correspond
12001  if(PrefDirVector.at(LastElementNumber(50)).XLinkPos == 1)
12002  {
12003  ELinkPos = 0;
12004  }
12005  if(PrefDirVector.at(LastElementNumber(51)).XLinkPos == 2)
12006  {
12007  ELinkPos = 3;
12008  }
12009  if(PrefDirVector.at(LastElementNumber(52)).XLinkPos == 3)
12010  {
12011  ELinkPos = 2;
12012  }
12013  if(PrefDirVector.at(LastElementNumber(53)).ELink == -1) // because was start element
12014  {
12015  PrefDirVector.at(LastElementNumber(54)).ELink = PrefDirVector.at(LastElementNumber(55)).Link[ELinkPos];
12016  PrefDirVector.at(LastElementNumber(56)).ELinkPos = ELinkPos;
12017  PrefDirVector.at(LastElementNumber(57)).CheckCount++;
12018  PrefDirVector.at(LastElementNumber(58)).CheckCount++;
12019  }
12020  break; // no point going any further
12021  }
12022  }
12023 // set EXNumber for last PrefDir element, unless already set
12024 // won't be set if was first element or a leading point
12025  if(PrefDirVector.at(LastElementNumber(59)).EXNumber == -1)
12026  {
12027 /* The order for entries & exits is as follows (1st no = entry, 2nd = exit):-
12028  int EXArray[32][2] = {
12029  {4,6},{2,8}, //horizontal & vertical
12030  {2,4},{6,2},{8,6},{4,8}, //sharp curves
12031  {1,6},{3,8},{9,4},{7,2},{1,8},{3,4},{9,2},{7,6}, //loose curves
12032  {1,9},{3,7} //forward & reverse diagonals
12033 */
12034 
12035  if(!(PrefDirVector.at(LastElementNumber(60)).EntryExitNumber()))
12036  {
12037  throw Exception("Error in EntryExitNumber 1");
12038  }
12039  PrefDirVector.at(LastElementNumber(61)).EXGraphicPtr = PrefDirVector.at(LastElementNumber(62)).GetPrefDirGraphicPtr();
12040  PrefDirVector.at(LastElementNumber(63)).EntryDirectionGraphicPtr = PrefDirVector.at(LastElementNumber(64)).GetDirectionPrefDirGraphicPtr();
12041  PrefDirVector.at(LastElementNumber(65)).CheckCount++;
12042  }
12043 // Last PrefDir element now complete
12044 
12045 // construct remaining PrefDir elements from searchvector
12046  for(unsigned int x = 0; x < SearchVector.size(); x++)
12047  {
12048  SearchElement = SearchVector.at(x);
12049  TPrefDirElement PrefDirElement(Track->TrackElementAt(75, SearchElement.TrackVectorPosition));
12050  PrefDirElement.TrackVectorPosition = SearchElement.TrackVectorPosition;
12051  PrefDirElement.ELink = SearchElement.ELink;
12052  PrefDirElement.ELinkPos = SearchElement.ELinkPos;
12053  PrefDirElement.XLink = SearchElement.XLink;
12054  PrefDirElement.XLinkPos = SearchElement.XLinkPos;
12055 // if XLink & XLinkPos not set don't account for them in CheckCount
12056  if(PrefDirElement.XLink == -1)
12057  {
12058  PrefDirElement.CheckCount = 6; // Hloc, VLoc, SpeedTag, ELink, ELinkPos,
12059  }
12060  // & TrackVectorPosition
12061  else
12062  {
12063  PrefDirElement.CheckCount = 8; // Hloc, VLoc, SpeedTag, ELink, ELinkPos,
12064  }
12065  // XLink, XLinkPos, TrackVectorPosition
12066 
12067 // set EXNumber (can't set EXNumber if XLink not set - if finished on a leading point
12068  if(PrefDirElement.XLink != -1)
12069  {
12070  if(!(PrefDirElement.EntryExitNumber()))
12071  {
12072  throw Exception("Error in EntryExitNumber 2");
12073  }
12074  PrefDirElement.EXGraphicPtr = PrefDirElement.GetPrefDirGraphicPtr();
12075  PrefDirElement.EntryDirectionGraphicPtr = PrefDirElement.GetDirectionPrefDirGraphicPtr();
12076  PrefDirElement.CheckCount++;
12077  // all values now incorporated if not a leading point
12078  }
12079 // store PrefDir element
12080  StorePrefDirElement(2, PrefDirElement);
12081  }
12082 // Can now validate if PrefDir finished, i.e. if buffers or continuation, else validate when 'AddPrefDir' button pressed
12083  if((LastElementPtr(0)->TrackType == Buffers) || (LastElementPtr(1)->TrackType == Continuation))
12084  {
12085  if(ValidatePrefDir(2))
12086  {
12087  ;
12088  } // error messages given within function
12089 
12090  }
12092 /* drop this, check dropped from search
12093  if(PrefDirVector.size() > 200)
12094  {
12095  ShowMessage("The selected track segment is becoming too long, until it is accepted further elements can only be added one at a time");
12096  }
12097 */
12098  Utilities->CallLogPop(148);
12099 }
12100 
12101 // ---------------------------------------------------------------------------
12102 
12103 bool TOnePrefDir::EndPossible(int Caller, bool &LeadingPoints)
12104 /*
12105  Return true if selected element is valid as a PrefDir end element, i.e. isn't leading points,
12106  and PrefDir isn't one element long. Used to enable the AddPrefDirButton during PrefDir building.
12107 */
12108 {
12109  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EndPossible");
12110  LeadingPoints = false;
12111  if(PrefDirVector.empty())
12112  {
12113  Utilities->CallLogPop(1786);
12114  return(false); // should never be empty but allow for it for safety
12115  }
12116  if(PrefDirVector.size() == 1)
12117  {
12118  Utilities->CallLogPop(149);
12119  return(false); // can't end if only one element
12120  }
12121 /*
12122  if((PrefDirVector.at(LastElementNumber()).TrackType != Points) &&
12123  (PrefDirVector.at(LastElementNumber()).TrackType != Crossover))
12124  {
12125  Utilities->CallLogPop(150);
12126  return true;
12127  }
12128 */
12129 // allow for anything but leading points
12130  if((PrefDirVector.at(LastElementNumber(66)).TrackType != Points) || (PrefDirVector.at(LastElementNumber(67)).ELinkPos == 1) ||
12131  (PrefDirVector.at(LastElementNumber(71)).ELinkPos == 3))
12132  {
12133  Utilities->CallLogPop(1776);
12134  return(true);
12135  }
12136  else
12137  {
12138  LeadingPoints = true;
12139  Utilities->CallLogPop(151);
12140  return(false);
12141  }
12142 }
12143 
12144 // ---------------------------------------------------------------------------
12145 
12147 /*
12148  Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default values,
12149  and that every element is connected to the next element
12150 */
12151 {
12152  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ValidatePrefDir");
12153  int Position;
12154  AnsiString ErrorString;
12155  bool Error = false;
12156 
12157  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
12158  {
12159  if(PrefDirVector.at(x).HLoc == -2000000000)
12160  {
12161  Error = true;
12162  ErrorString = "HLoc";
12163  Position = x;
12164  }
12165  if(PrefDirVector.at(x).VLoc == -2000000000)
12166  {
12167  Error = true;
12168  ErrorString = "VLoc";
12169  Position = x;
12170  }
12171  if(PrefDirVector.at(x).ELink == -1)
12172  {
12173  Error = true;
12174  ErrorString = "ELink";
12175  Position = x;
12176  }
12177  if(PrefDirVector.at(x).ELinkPos == -1)
12178  {
12179  Error = true;
12180  ErrorString = "ELinkPos";
12181  Position = x;
12182  }
12183  if(PrefDirVector.at(x).XLink == -1)
12184  {
12185  Error = true;
12186  ErrorString = "XLink";
12187  Position = x;
12188  }
12189  if(PrefDirVector.at(x).XLinkPos == -1)
12190  {
12191  Error = true;
12192  ErrorString = "XLinkPos";
12193  Position = x;
12194  }
12195  if(PrefDirVector.at(x).SpeedTag == 0)
12196  {
12197  Error = true;
12198  ErrorString = "Tag";
12199  Position = x;
12200  }
12201  if(PrefDirVector.at(x).TrackVectorPosition == -1)
12202  {
12203  Error = true;
12204  ErrorString = "TrackVectorPosition";
12205  Position = x;
12206  }
12207  if(PrefDirVector.at(x).EXNumber == -1)
12208  {
12209  Error = true;
12210  ErrorString = "EXNumber";
12211  Position = x;
12212  }
12213  if(PrefDirVector.at(x).CheckCount != 9)
12214  // HLoc, VLoc, SpeedTag, TrackVectorPosition, ELink, ELinkPos, XLink, XLinkPos & EXNumber
12215  {
12216  Error = true;
12217  ErrorString = "CheckCount";
12218  Position = x;
12219  }
12220 // extra checks
12221  if(PrefDirVector.at(x).EXGraphicPtr == 0)
12222  {
12223  Error = true;
12224  ErrorString = "EntryGraphicPtr";
12225  Position = x;
12226  }
12227  if(PrefDirVector.at(x).EntryDirectionGraphicPtr == 0)
12228  {
12229  Error = true;
12230  ErrorString = "EntryDirectionGraphicPtr";
12231  Position = x;
12232  }
12233 // end of extra checks
12234  if(x > 0)
12235  {
12236  if(PrefDirVector.at(x - 1).Conn[PrefDirVector.at(x - 1).XLinkPos] != PrefDirVector.at(x).TrackVectorPosition)
12237  {
12238  Error = true;
12239  ErrorString = "Last XLink not connected to this element";
12240  Position = x;
12241  }
12242  }
12243  }
12244  if(Error)
12245  {
12246  throw Exception("Error at " + AnsiString(Position) + " " + ErrorString);
12247  }
12248  else
12249  {
12250  Utilities->CallLogPop(153);
12251  return(true);
12252  }
12253 }
12254 
12255 // ---------------------------------------------------------------------------
12256 
12257 bool TOnePrefDir::GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
12258 /*
12259  This is only called during PrefDir build or distance setting. It truncates at & including the first element in the PrefDir vector
12260  that matches H & V. After the truncate the final element of the remaining PrefDir has its data members reset
12261  to the same defaults as would be the case if the PrefDir had been built up to that point - i.e. for first element
12262  or a leading point.
12263 */
12264 {
12265  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPrefDirTruncateElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
12266  for(unsigned int x = 0; x < (PrefDirVector.size()); x++)
12267  {
12268  if((PrefDirVector.at(x).HLoc == HLoc) && (PrefDirVector.at(x).VLoc == VLoc))
12269  {
12270  for(int PrefDirVecPos = (PrefDirVector.size() - 1); PrefDirVecPos >= (int)x; PrefDirVecPos--) // has to be int or will underflow at x==0
12271  {
12272  ErasePrefDirElementAt(1, PrefDirVecPos);
12273  }
12274  if(PrefDirVector.size() == 0)
12275  {
12276  Utilities->CallLogPop(154);
12277  return(true);
12278  }
12279  if(PrefDirVector.size() == 1)
12280  {
12281  PrefDirVector.at(x - 1).ELinkPos = -1;
12282  PrefDirVector.at(x - 1).ELink = -1;
12283  PrefDirVector.at(x - 1).XLinkPos = -1;
12284  PrefDirVector.at(x - 1).XLink = -1;
12285  PrefDirVector.at(x - 1).EXNumber = -1;
12286  PrefDirVector.at(x - 1).EXGraphicPtr = 0;
12287  PrefDirVector.at(x - 1).EntryDirectionGraphicPtr = 0;
12288  PrefDirVector.at(x - 1).CheckCount = PrefDirVector.at(x - 1).CheckCount - 5;
12289  Utilities->CallLogPop(155);
12290  return(true);
12291  }
12292  // here with truncate element not first element, so ELink & ELinkPos set
12293  // unset XLink & Pos if a leading point
12294  if(PrefDirVector.at(x - 1).Config[PrefDirVector.at(x - 1).ELinkPos] == Lead)
12295  {
12296  PrefDirVector.at(x - 1).XLinkPos = -1;
12297  PrefDirVector.at(x - 1).XLink = -1;
12298  PrefDirVector.at(x - 1).EXNumber = -1;
12299  PrefDirVector.at(x - 1).EXGraphicPtr = 0;
12300  PrefDirVector.at(x - 1).EntryDirectionGraphicPtr = 0;
12301  PrefDirVector.at(x - 1).CheckCount = PrefDirVector.at(x - 1).CheckCount - 3;
12302  Utilities->CallLogPop(156);
12303  return(true);
12304  }
12305  Utilities->CallLogPop(157);
12306  return(true);
12307  }
12308  }
12309  Utilities->CallLogPop(158);
12310  return(false);
12311 }
12312 
12313 // ---------------------------------------------------------------------------
12314 
12315 void TOnePrefDir::PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp)
12316 const // PrefDirRoute = PrefDircall or routecall for PrefDir or route; true for BuildingPrefDir
12317 /*
12318  PrefDir and route track marker, including direction markers. Function used for both PrefDirs (PrefDirRoute == PrefDirCall) and routes
12319  (PrefDirRoute == RouteCall). The graphics for marker colours and direction are already stored in all PrefDirElements in
12320  TOnePrefDir and TOneRoute, and this function is called to display them, all in the case of a PrefDir, but for a route only the
12321  first and last elements have direction markers. No markers are displayed if a train is present on an element. Also no
12322  display if EXGraphicPtr not set. If building a PrefDir (BuildingPrefDir true) then the start and end rectangles are also
12323  displayed.
12324 */
12325 {
12326  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PrefDirMarker," + AnsiString(PrefDirRoute) + "," +
12327  AnsiString((short)BuildingPrefDir));
12328  int HPos, VPos;
12329 
12330  if(PrefDirSize() == 0)
12331  {
12332  Utilities->CallLogPop(159);
12333  return;
12334  }
12335  for(unsigned int x = 0; x < PrefDirSize(); x++)
12336  {
12337  TPrefDirElement TempPrefDirElement = PrefDirVector.at(x);
12338 // if(Track->TrackElementAt(76, TempPrefDirElement.TrackVectorPosition).TrainIDOnElement > -1) continue;
12339 // don't plot route element if train present - dropped above as train departing only replotted the part of the route
12340 // that the train was on. Ensure though that whenever plot a route replot trains after else route will overwrite train
12341  // without the above, if route replotted in ClearandRebuildRailway when train is straddling 3 elements
12342  // and before the next train update, then the route element corresponding to the LagElement will be plotted,
12343  // only the front half of which will be overplotted by the back of the train, then when the train is
12344  // updated the route image will remain plotted and stay on screen until a later ClearandRebuildRailway
12345  if(TempPrefDirElement.EXGraphicPtr != 0) // Note: will be 0 if first element or last as leading point
12346  {
12347  Disp->PlotOutput(12, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EXGraphicPtr);
12348  if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && (PrefDirRoute == PrefDirCall)) // PrefDir
12349  {
12350  Disp->PlotOutput(13, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
12351  }
12352  else if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && (PrefDirRoute == RouteCall) && PrefDirSize() > 1)
12353  // Route, no direction if a single element
12354  {
12355  if(x == 0)
12356  {
12357  Disp->PlotOutput(14, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
12358  }
12359  if(x == (PrefDirSize() - 1))
12360  {
12361  Disp->PlotOutput(15, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
12362  }
12363  }
12364  }
12365  }
12366 
12367 // set start & end element colours if building a PrefDir
12368  if((PrefDirRoute == PrefDirCall) && BuildingPrefDir)
12369  {
12370  HPos = GetFixedPrefDirElementAt(4, 0).HLoc * 16;
12371  VPos = GetFixedPrefDirElementAt(5, 0).VLoc * 16;
12372  Disp->Rectangle(1, HPos, VPos, clB0G0R5, 2, 2); // medium red rectangle
12373  // set last element colour
12374  if(PrefDirSize() > 1)
12375  {
12376  unsigned int LatestPos = PrefDirSize() - 1;
12377  HPos = GetFixedPrefDirElementAt(6, LatestPos).HLoc * 16;
12378  VPos = GetFixedPrefDirElementAt(7, LatestPos).VLoc * 16;
12379  Disp->Rectangle(2, HPos, VPos, clB5G0R0, 4, 2); // smaller blue rectangle
12380  }
12381  }
12382  Disp->Update();
12383  Utilities->CallLogPop(160);
12384 }
12385 
12386 // ---------------------------------------------------------------------------
12387 
12389 /*
12390  Similar to PrefDirMarker but used only to mark EveryPrefDir - red for unidirectional PrefDir & green for bidirectional
12391  Colours taken from the route colours. Plot red first so green overwrites for bidirectional points.
12392 */
12393 {
12394  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EveryPrefDirMarker");
12395  if(PrefDirSize() == 0)
12396  {
12397  Utilities->CallLogPop(1547);
12398  return;
12399  }
12400  int H, V, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
12401  bool FoundFlag;
12403  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
12404 
12405  while(MMIT != PrefDir4MultiMap.end())
12406  {
12407  H = MMIT->first.first;
12408  V = MMIT->first.second;
12409  GetVectorPositionsFromPrefDir4MultiMap(6, H, V, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
12410  // always found in order, any missing have PrefDirPosx == -1
12411  if(PrefDirPos0 > -1)
12412  {
12413  PrefDirElement0 = GetFixedPrefDirElementAt(170, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
12414  }
12415  if(PrefDirPos1 > -1)
12416  {
12417  PrefDirElement1 = GetFixedPrefDirElementAt(171, PrefDirPos1);
12418  }
12419  if(PrefDirPos2 > -1)
12420  {
12421  PrefDirElement2 = GetFixedPrefDirElementAt(172, PrefDirPos2);
12422  }
12423  if(PrefDirPos3 > -1)
12424  {
12425  PrefDirElement3 = GetFixedPrefDirElementAt(173, PrefDirPos3);
12426  }
12427  if(PrefDirPos3 > -1) // 4 found, mark all PrefDirs bidirectional (operator == ensures no duplicates in ConsolidatePrefDirs)
12428  {
12429  // need to plot all 4 in order to obtain all the direction graphics
12430  Disp->PlotOutput(77, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12431  Disp->PlotOutput(78, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12432  Disp->PlotOutput(79, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12433  Disp->PlotOutput(80, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12434  Disp->PlotOutput(81, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
12435  Disp->PlotOutput(82, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
12436  Disp->PlotOutput(83, (H * 16), (V * 16), PrefDirElement3.GetRouteGraphicPtr(false, true)); // green
12437  Disp->PlotOutput(84, (H * 16), (V * 16), PrefDirElement3.GetDirectionRouteGraphicPtr(false, true)); // green
12438  MMIT++;
12439  MMIT++;
12440  MMIT++;
12441  MMIT++;
12442  }
12443  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
12444  {
12445  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
12446  {
12447  // 0 & 1 constitute the bidirectional PrefDir
12448  Disp->PlotOutput(89, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, false)); // red
12449  Disp->PlotOutput(90, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, false)); // red
12450  Disp->PlotOutput(85, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12451  Disp->PlotOutput(86, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12452  Disp->PlotOutput(87, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12453  Disp->PlotOutput(88, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12454  MMIT++;
12455  MMIT++;
12456  MMIT++;
12457  }
12458  else if(PrefDirElement0.EXNumber == PrefDirElement2.EXNumber)
12459  {
12460  // 0 & 2 constitute the bidirectional PrefDir
12461  Disp->PlotOutput(95, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
12462  Disp->PlotOutput(96, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
12463  Disp->PlotOutput(91, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12464  Disp->PlotOutput(92, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12465  Disp->PlotOutput(93, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
12466  Disp->PlotOutput(94, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
12467  MMIT++;
12468  MMIT++;
12469  MMIT++;
12470  }
12471  else
12472  {
12473  // 1 & 2 constitute the bidirectional PrefDir
12474  Disp->PlotOutput(101, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
12475  Disp->PlotOutput(102, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
12476  Disp->PlotOutput(97, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12477  Disp->PlotOutput(98, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12478  Disp->PlotOutput(99, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
12479  Disp->PlotOutput(100, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
12480  MMIT++;
12481  MMIT++;
12482  MMIT++;
12483  }
12484  }
12485  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
12486  {
12487  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
12488  {
12489  // 0 & 1 constitute the bidirectional PrefDir
12490  Disp->PlotOutput(103, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12491  Disp->PlotOutput(104, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12492  Disp->PlotOutput(105, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12493  Disp->PlotOutput(106, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12494  MMIT++;
12495  MMIT++;
12496  }
12497  else
12498  {
12499  // 2 unidirectional PrefDirs
12500  Disp->PlotOutput(107, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
12501  Disp->PlotOutput(108, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
12502  Disp->PlotOutput(109, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
12503  Disp->PlotOutput(110, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
12504  MMIT++;
12505  MMIT++;
12506  }
12507  }
12508  else if(PrefDirPos0 > -1) // 1 found, must be unidirectional
12509  {
12510  Disp->PlotOutput(111, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
12511  Disp->PlotOutput(112, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
12512  MMIT++;
12513  }
12514  }
12515  Disp->Update();
12516  Utilities->CallLogPop(1548);
12517 }
12518 
12519 // ---------------------------------------------------------------------------
12520 
12521 void TOnePrefDir::LoadOldPrefDir(int Caller, std::ifstream &VecFile)
12522 {
12523  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOldPrefDir");
12524  int TempInt;
12525 
12526  ClearPrefDir();
12527  int NumberOfPrefDirElements = 0;
12528 
12529  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
12530  for(int x = 0; x < NumberOfPrefDirElements; x++)
12531  {
12532  VecFile >> TempInt; // TrackVectorPosition
12533  TPrefDirElement LoadPrefDirElement(Track->TrackElementAt(714, TempInt));
12534  LoadPrefDirElement.TrackVectorPosition = TempInt;
12535  VecFile >> TempInt;
12536  LoadPrefDirElement.ELink = TempInt;
12537  VecFile >> TempInt;
12538  LoadPrefDirElement.ELinkPos = TempInt;
12539  VecFile >> TempInt;
12540  LoadPrefDirElement.XLink = TempInt;
12541  VecFile >> TempInt;
12542  LoadPrefDirElement.XLinkPos = TempInt;
12543  VecFile >> TempInt;
12544  LoadPrefDirElement.EXNumber = TempInt;
12545  VecFile >> TempInt;
12546  LoadPrefDirElement.CheckCount = TempInt;
12547  LoadPrefDirElement.IsARoute = Utilities->LoadFileBool(VecFile);
12548  LoadPrefDirElement.AutoSignals = Utilities->LoadFileBool(VecFile);
12549  LoadPrefDirElement.PrefDirRoute = Utilities->LoadFileBool(VecFile);
12550  if(!(LoadPrefDirElement.IsARoute))
12551  {
12552  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetPrefDirGraphicPtr();
12553  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionPrefDirGraphicPtr();
12554  }
12555  else
12556  {
12557  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetRouteGraphicPtr(LoadPrefDirElement.AutoSignals, LoadPrefDirElement.PrefDirRoute);
12558  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionRouteGraphicPtr(LoadPrefDirElement.AutoSignals,
12559  LoadPrefDirElement.PrefDirRoute);
12560  }
12561  StorePrefDirElement(5, LoadPrefDirElement);
12562  Utilities->LoadFileString(VecFile); // marker
12563  }
12565  Utilities->CallLogPop(161);
12566 }
12567 
12568 // ---------------------------------------------------------------------------
12569 
12570 void TOnePrefDir::LoadPrefDir(int Caller, std::ifstream &VecFile)
12571 {
12572  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadPrefDir");
12573  int TempInt;
12574 
12575  ClearPrefDir();
12576  int NumberOfPrefDirElements = 0;
12577 
12578  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
12579  for(int x = 0; x < NumberOfPrefDirElements; x++)
12580  {
12581  VecFile >> TempInt; // PrefDirVectorPosition, not used in load
12582  VecFile >> TempInt; // TrackVectorPosition
12583  TPrefDirElement LoadPrefDirElement(Track->TrackElementAt(781, TempInt)); //Loads all basic TrackElement values incl HLoc, VLoc & SpeedTag
12584  LoadPrefDirElement.TrackVectorPosition = TempInt;
12585  VecFile >> TempInt;
12586  LoadPrefDirElement.ELink = TempInt;
12587  VecFile >> TempInt;
12588  LoadPrefDirElement.ELinkPos = TempInt;
12589  VecFile >> TempInt;
12590  LoadPrefDirElement.XLink = TempInt;
12591  VecFile >> TempInt;
12592  LoadPrefDirElement.XLinkPos = TempInt;
12593  VecFile >> TempInt;
12594  LoadPrefDirElement.EXNumber = TempInt;
12595  VecFile >> TempInt;
12596  LoadPrefDirElement.CheckCount = TempInt;
12597  LoadPrefDirElement.IsARoute = Utilities->LoadFileBool(VecFile);
12598  LoadPrefDirElement.AutoSignals = Utilities->LoadFileBool(VecFile);
12599  LoadPrefDirElement.PrefDirRoute = Utilities->LoadFileBool(VecFile);
12600  if(!(LoadPrefDirElement.IsARoute))
12601  {
12602  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetPrefDirGraphicPtr();
12603  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionPrefDirGraphicPtr();
12604  }
12605  else
12606  {
12607  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetRouteGraphicPtr(LoadPrefDirElement.AutoSignals, LoadPrefDirElement.PrefDirRoute);
12608  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionRouteGraphicPtr(LoadPrefDirElement.AutoSignals,
12609  LoadPrefDirElement.PrefDirRoute);
12610  }
12611  StorePrefDirElement(0, LoadPrefDirElement);
12612  AnsiString MarkerString = Utilities->LoadFileString(VecFile); // marker
12613  }
12615  Utilities->CallLogPop(1509);
12616 }
12617 
12618 // ---------------------------------------------------------------------------
12619 
12620 bool TOnePrefDir::CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile) // returns false if no more PrefDirs to check
12621 /*
12622  Called before PrefDir loading as part of the FileIntegrityCheck function, in case there is an error in the
12623  file. Very similar to LoadPrefDir but with value checks instead of storage in PrefDirVector.
12624 */
12625 {
12626  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckOnePrefDir");
12627  int TempInt;
12628  int NumberOfPrefDirElements = 0;
12629 
12630  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
12631  if((NumberOfPrefDirElements < 0) || (NumberOfPrefDirElements > 1000000))
12632  {
12633  Utilities->CallLogPop(1152);
12634  return(false);
12635  }
12636  for(int x = 0; x < NumberOfPrefDirElements; x++)
12637  {
12638  if(!Utilities->CheckFileInt(VecFile, x, x)) // vector number
12639  {
12640  Utilities->CallLogPop(1766);
12641  return(false);
12642  }
12643  VecFile >> TempInt;
12644  if((TempInt < 0) || (TempInt >= NumberOfActiveElements)) // TrackVectorPosition
12645  {
12646  Utilities->CallLogPop(163);
12647  return(false);
12648  }
12649  VecFile >> TempInt;
12650  if((TempInt < -1) || (TempInt > 9)) // ELink
12651  {
12652  Utilities->CallLogPop(162);
12653  return(false);
12654  }
12655  VecFile >> TempInt;
12656  if((TempInt < -1) || (TempInt > 3)) // ELinkPos
12657  {
12658  Utilities->CallLogPop(164);
12659  return(false);
12660  }
12661  VecFile >> TempInt;
12662  if((TempInt < -1) || (TempInt > 9)) // XLink
12663  {
12664  Utilities->CallLogPop(165);
12665  return(false);
12666  }
12667  VecFile >> TempInt;
12668  if((TempInt < -1) || (TempInt > 3)) // XLinkPos
12669  {
12670  Utilities->CallLogPop(166);
12671  return(false);
12672  }
12673  VecFile >> TempInt;
12674  if((TempInt < -1) || (TempInt > 27)) // EXNumber
12675  {
12676  Utilities->CallLogPop(167);
12677  return(false);
12678  }
12679  VecFile >> TempInt;
12680  if(TempInt != 9) // CheckCount - reduced to 11 after NextPrefDirElement dropped &
12681  // to 9 after End & Stop dropped. Leaving HLoc, VLoc, SpeedTag, TrackVectorPosition, ELink,
12682  // ELinkPos, XLink, XLinkPos & EXNumber
12683  {
12684  Utilities->CallLogPop(168);
12685  return(false);
12686  }
12687  VecFile >> TempInt;
12688  if((TempInt != 0) && (TempInt != 1)) // RouteElement
12689  {
12690  Utilities->CallLogPop(1147);
12691  return(false);
12692  }
12693  VecFile >> TempInt;
12694  if((TempInt != 0) && (TempInt != 1)) // AutoSignals
12695  {
12696  Utilities->CallLogPop(1510);
12697  return(false);
12698  }
12699  VecFile >> TempInt;
12700  if((TempInt != 0) && (TempInt != 1)) // PrefDirRoute
12701  {
12702  Utilities->CallLogPop(1148);
12703  return(false);
12704  }
12705  if(!Utilities->CheckFileStringZeroDelimiter(VecFile)) // marker
12706  {
12707  Utilities->CallLogPop(1700);
12708  return(false);
12709  }
12710  }
12711  Utilities->CallLogPop(169);
12712  return(true);
12713 }
12714 
12715 // ---------------------------------------------------------------------------
12716 
12717 void TOnePrefDir::SavePrefDirVector(int Caller, std::ofstream &VecFile)
12718 {
12719  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SavePrefDir");
12720  int NumberOfPrefDirElements = PrefDirVector.size();
12721 
12722  Utilities->SaveFileInt(VecFile, NumberOfPrefDirElements);
12723  for(int y = 0; y < NumberOfPrefDirElements; y++)
12724  {
12725  VecFile << y << '\n'; // extra
12726  VecFile << PrefDirVector.at(y).TrackVectorPosition << '\n'; //When reloaded values for HLoc, VLoc & SpeedTag are derived from the TrackElement at TrackVectorPosition
12727  VecFile << PrefDirVector.at(y).ELink << '\n'; //so all 9 critical values are set
12728  VecFile << PrefDirVector.at(y).ELinkPos << '\n';
12729  VecFile << PrefDirVector.at(y).XLink << '\n';
12730  VecFile << PrefDirVector.at(y).XLinkPos << '\n';
12731  VecFile << PrefDirVector.at(y).EXNumber << '\n';
12732  VecFile << PrefDirVector.at(y).CheckCount << '\n';
12733  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).IsARoute);
12734  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).AutoSignals);
12735  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).PrefDirRoute);
12736  if(y == (NumberOfPrefDirElements - 1)) // last element, write a longer delimiter
12737  {
12738  VecFile << "************" << '\0' << '\n'; // marker
12739  }
12740  else
12741  {
12742  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
12743  }
12744  }
12745  Utilities->CallLogPop(170);
12746 }
12747 
12748 // ---------------------------------------------------------------------------
12749 
12750 void TOnePrefDir::SaveSearchVector(int Caller, std::ofstream &VecFile)
12751 {
12752  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSearchVector");
12753  int NumberOfSearchElements = SearchVector.size();
12754 
12755  Utilities->SaveFileInt(VecFile, NumberOfSearchElements);
12756  for(int y = 0; y < NumberOfSearchElements; y++)
12757  {
12758  VecFile << y << '\n'; // extra
12759  VecFile << SearchVector.at(y).TrackVectorPosition << '\n';
12760  VecFile << SearchVector.at(y).ELink << '\n';
12761  VecFile << SearchVector.at(y).ELinkPos << '\n';
12762  VecFile << SearchVector.at(y).XLink << '\n';
12763  VecFile << SearchVector.at(y).XLinkPos << '\n';
12764  VecFile << SearchVector.at(y).EXNumber << '\n';
12765  VecFile << SearchVector.at(y).CheckCount << '\n';
12766  Utilities->SaveFileBool(VecFile, SearchVector.at(y).IsARoute);
12767  Utilities->SaveFileBool(VecFile, SearchVector.at(y).AutoSignals);
12768  Utilities->SaveFileBool(VecFile, SearchVector.at(y).PrefDirRoute);
12769  if(y == (NumberOfSearchElements - 1)) // last element, write a longer delimiter
12770  {
12771  VecFile << "************" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
12772  }
12773  else
12774  {
12775  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
12776  }
12777  }
12778  Utilities->CallLogPop(1847);
12779 }
12780 
12781 // ---------------------------------------------------------------------------
12782 
12783 void TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
12784 /*
12785  Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails
12786  erasing up to four elements (2 directions and 2 tracks for 4-entry elements).
12787 */
12788 {
12789  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseFromPrefDirVectorAnd4MultiMap," + AnsiString(HLoc) + "," +
12790  AnsiString(VLoc));
12791  int VecPos = GetOnePrefDirPosition(1, HLoc, VLoc);
12792 
12793  if(VecPos > -1)
12794  {
12795  ErasePrefDirElementAt(2, VecPos); // max of 4 to be erased
12796  }
12797  else
12798  {
12799  Utilities->CallLogPop(171);
12800  return;
12801  }
12802  VecPos = GetOnePrefDirPosition(2, HLoc, VLoc);
12803  if(VecPos > -1)
12804  {
12805  ErasePrefDirElementAt(3, VecPos);
12806  }
12807  else
12808  {
12809  Utilities->CallLogPop(172);
12810  return;
12811  }
12812  VecPos = GetOnePrefDirPosition(3, HLoc, VLoc);
12813  if(VecPos > -1)
12814  {
12815  ErasePrefDirElementAt(4, VecPos);
12816  }
12817  else
12818  {
12819  Utilities->CallLogPop(173);
12820  return;
12821  }
12822  VecPos = GetOnePrefDirPosition(4, HLoc, VLoc);
12823  if(VecPos > -1)
12824  {
12825  ErasePrefDirElementAt(5, VecPos);
12826  }
12827  else
12828  {
12829  Utilities->CallLogPop(174);
12830  return;
12831  }
12832  Utilities->CallLogPop(175);
12833 }
12834 
12835 // ---------------------------------------------------------------------------
12836 /*
12837  void TOnePrefDir::EraseCorruptedElementsAfterTrackBuild()//Delete any PrefDir elements that are no longer valid
12838  //Not needed after new TrackErase (now EraseTrackElement), where blank elements aren't used
12839 
12840  When track is rebuilt any elements that are dispensed with aren't erased immediately, a blank element is put
12841  in their place so that existing linkages will be preserved. At this stage this function is called to remove
12842  any elements in PrefDirVector that correspond directly to blank track elements or that are connected to blank track
12843  elements. Finally the track is reconnected using Track->TryToConnectTrack (if won't connect then returns to
12844  AddTrackStage build mode for corrections to be made) and then EveryPrefDir->RebuildPrefDirVector() called to reset
12845  PrefDirVector to correspond to the new track layout.
12846 
12847  {
12848  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EraseCorruptedElementsAfterTrackBuild");
12849  if(PrefDirSize() == 0)
12850  {
12851  Utilities->CallLogPop(176);
12852  return;
12853  }
12854  for(int x=(PrefDirVector.size()-1);x>=0;x--)
12855  {
12856  int TV = PrefDirVector.at(x).TrackVectorPosition;
12857  int ConnELink = PrefDirVector.at(x).Conn[PrefDirVector.at(x).ELinkPos];
12858  int ConnXLink = PrefDirVector.at(x).Conn[PrefDirVector.at(x).XLinkPos];
12859  if(Track->BlankElementAt(0, TV))
12860  {
12861  ErasePrefDirElementAt(6, x);
12862  }
12863  //if was a blankelement at x then ConnELink and ConnXLink both -1
12864  else if((ConnELink > -1) && (Track->BlankElementAt(1, ConnELink)))
12865  {
12866  ErasePrefDirElementAt(7, x);
12867  }
12868  //if both ConnELink and ConnXLink correspond to blank elements then OK, element only
12869  //needs to be erased once, but if don't use 'else' then will erase two elements
12870  //since 'x' will correspond to the element after the first erased element
12871  else if((ConnXLink > -1) && (Track->BlankElementAt(2, ConnXLink)))
12872  {
12873  ErasePrefDirElementAt(8, x);
12874  }
12875  }
12876  Utilities->CallLogPop(177);
12877  }
12878 */
12879 // ---------------------------------------------------------------------------
12880 
12881 void TOnePrefDir::ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
12882 /*
12883  This is used to add InputPrefDir's PrefDirVector to TOnePrefDir's PrefDirVector except where it already
12884  exists in TOnePrefDir. In practice it adds ConstructPrefDir to EveryPrefDir.
12885 */
12886 {
12887  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConsolidatePrefDirs");
12888  bool AlreadyPresent, FoundFlag;
12889  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
12890 
12891  for(unsigned int x = 0; x < InputPrefDir->PrefDirSize(); x++)
12892  {
12893  TPrefDirElement TempElement = InputPrefDir->PrefDirVector.at(x);
12894  GetVectorPositionsFromPrefDir4MultiMap(1, TempElement.HLoc, TempElement.VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
12895  AlreadyPresent = false;
12896  if(FoundFlag)
12897  {
12898  if((PrefDirPos0 > -1) && (TempElement == GetFixedPrefDirElementAt(8, PrefDirPos0)))
12899  {
12900  AlreadyPresent = true;
12901  }
12902  if((PrefDirPos1 > -1) && (TempElement == GetFixedPrefDirElementAt(9, PrefDirPos1)))
12903  {
12904  AlreadyPresent = true;
12905  }
12906  if((PrefDirPos2 > -1) && (TempElement == GetFixedPrefDirElementAt(10, PrefDirPos2)))
12907  {
12908  AlreadyPresent = true;
12909  }
12910  if((PrefDirPos3 > -1) && (TempElement == GetFixedPrefDirElementAt(11, PrefDirPos3)))
12911  {
12912  AlreadyPresent = true;
12913  }
12914  }
12915  if(!AlreadyPresent)
12916  {
12917  StorePrefDirElement(4, TempElement);
12918  }
12919  }
12921  Utilities->CallLogPop(178);
12922 }
12923 /* earlier brute force search
12924  for(unsigned int x = 0;x<InputPrefDir->PrefDirSize();x++)
12925  {
12926  TPrefDirElement TempElement = InputPrefDir->GetFixedPrefDirElementAt(12, x);
12927  bool AlreadyPresent = false;
12928  for(unsigned int y = 0;y<PrefDirSize();y++)
12929  {
12930  if(TempElement == GetFixedPrefDirElementAt(13, y)) AlreadyPresent = true;
12931  }
12932  if(!AlreadyPresent) StorePrefDirElement(, TempElement);
12933  }
12934 */
12935 
12936 // ---------------------------------------------------------------------------
12937 
12939 /*
12940  Rebuild from Trackmap, doesn't affect PrefDir4MultiMap.
12941  After a track build, but before the track is reconnected, all invalid PrefDir elements in TOnePrefDir
12942  (i.e. in EveryPrefDir) are erased. Hence at that stage all the PrefDir elements are valid and correspond to
12943  the track elements at relevant H & V positions. However, after the track is reconnected, the TrackVector
12944  positions are likely to have changed, so this function is called to reset all the necessary connections and
12945  TrackVector positions. To be on the safe side all the TrackElement values that are additional to
12946  TFixedTrackPiece (apart from TrainIDs, these only present during operation) are reset, though the others
12947  shouldn't have changed.
12948 */
12949 {
12950  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildPrefDirVector");
12951  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
12952  {
12953  bool FoundFlag;
12954  int VecPos = Track->GetVectorPositionFromTrackMap(10, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
12955  if(FoundFlag)
12956  {
12957  PrefDirVector.at(x).TrackVectorPosition = VecPos;
12958  PrefDirVector.at(x).LocationName = Track->TrackElementAt(78, VecPos).LocationName;
12959  PrefDirVector.at(x).ActiveTrackElementName = Track->TrackElementAt(79, VecPos).ActiveTrackElementName;
12960  PrefDirVector.at(x).ElementID = Track->TrackElementAt(80, VecPos).ElementID;
12961  PrefDirVector.at(x).Attribute = Track->TrackElementAt(81, VecPos).Attribute;
12962  for(unsigned int z = 0; z < 4; z++)
12963  {
12964  PrefDirVector.at(x).Conn[z] = Track->TrackElementAt(82, VecPos).Conn[z];
12965  PrefDirVector.at(x).ConnLinkPos[z] = Track->TrackElementAt(83, VecPos).ConnLinkPos[z];
12966  }
12967  }
12968  else
12969  {
12970  throw Exception("Error in RebuildPrefDirVector - PrefDirVector is unsafe");
12971  }
12972  }
12973  Utilities->CallLogPop(179);
12974 }
12975 
12976 // ---------------------------------------------------------------------------
12977 
12979 /*
12980  Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefDir & PrefDir4MultiMap.
12981 */
12982 {
12983  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDirAgainstTrackVector");
12984  bool DiscrepancyFound = false;
12985 
12986  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
12987  {
12988  bool FoundFlag;
12989  int VecPos = Track->GetVectorPositionFromTrackMap(39, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
12990  if(FoundFlag)
12991  {
12992  TPrefDirElement PE = PrefDirVector.at(x);
12993  if(PE.TrackVectorPosition != VecPos)
12994  {
12995  DiscrepancyFound = true;
12996  break;
12997  }
12998  if((PE.GetELinkPos() < 0) || (PE.GetELinkPos() > 3))
12999  {
13000  DiscrepancyFound = true;
13001  break;
13002  }
13003  if((PE.GetXLinkPos() < 0) || (PE.GetXLinkPos() > 3))
13004  {
13005  DiscrepancyFound = true;
13006  break;
13007  }
13008  if(PE.ELink != Track->TrackElementAt(710, VecPos).Link[PE.GetELinkPos()])
13009  {
13010  DiscrepancyFound = true;
13011  break;
13012  }
13013  if(PE.XLink != Track->TrackElementAt(711, VecPos).Link[PE.GetXLinkPos()])
13014  {
13015  DiscrepancyFound = true;
13016  break;
13017  }
13018  }
13019  else
13020  {
13021  DiscrepancyFound = true;
13022  }
13023  }
13024  if(DiscrepancyFound)
13025  {
13026  ShowMessage("Discrepancies found in the preferred direction file, preferred directions will be cleared");
13027  ClearPrefDir(); // also clears multimap
13028  }
13029  Utilities->CallLogPop(1436);
13030 }
13031 
13032 // ---------------------------------------------------------------------------
13033 
13035 /*
13036  Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4MultiMap.
13037  return true for OK
13038 */
13039 {
13040  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDirAgainstTrackVectorNoMessage");
13041  bool DiscrepancyFound = false;
13042 
13043  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
13044  {
13045  bool FoundFlag;
13046  int VecPos = Track->GetVectorPositionFromTrackMap(36, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
13047  if(FoundFlag)
13048  {
13049  TPrefDirElement PE = PrefDirVector.at(x);
13050  if(PE.TrackVectorPosition != VecPos)
13051  {
13052  DiscrepancyFound = true;
13053  }
13054  if((PE.GetELinkPos() < 0) || (PE.GetELinkPos() > 3))
13055  {
13056  DiscrepancyFound = true;
13057  break;
13058  }
13059  if((PE.GetXLinkPos() < 0) || (PE.GetXLinkPos() > 3))
13060  {
13061  DiscrepancyFound = true;
13062  break;
13063  }
13064  if(PE.ELink != Track->TrackElementAt(715, VecPos).Link[PE.GetELinkPos()])
13065  {
13066  DiscrepancyFound = true;
13067  break;
13068  }
13069  if(PE.XLink != Track->TrackElementAt(716, VecPos).Link[PE.GetXLinkPos()])
13070  {
13071  DiscrepancyFound = true;
13072  break;
13073  }
13074  }
13075  else
13076  {
13077  DiscrepancyFound = true;
13078  }
13079  }
13080  Utilities->CallLogPop(1512);
13081  return(!DiscrepancyFound);
13082 }
13083 
13084 // ---------------------------------------------------------------------------
13085 
13086 void TOnePrefDir::CheckPrefDir4MultiMap(int Caller) // test
13087 /*
13088  Test function to check correspondence between PrefDirVector and PrefDir4MultiMap for each element in
13089  turn and for the overall sizes.
13090 */
13091 {
13092  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDir4MultiMap");
13093  bool FoundFlag = false;
13094  int PrefDir0, PrefDir1, PrefDir2, PrefDir3;
13095 
13096  for(unsigned int a = 0; a < PrefDirVector.size(); a++)
13097  {
13098  TPrefDirElement CheckElement = PrefDirVector.at(a);
13099  GetVectorPositionsFromPrefDir4MultiMap(2, CheckElement.HLoc, CheckElement.VLoc, FoundFlag, PrefDir0, PrefDir1, PrefDir2, PrefDir3);
13100  if(!FoundFlag)
13101  {
13102  throw Exception("CheckPrefDir4MultiMap Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
13103  " in PrefDir4MultiMap, Caller=" + (AnsiString)Caller);
13104  }
13105  if((PrefDir0 != (int)a) && (PrefDir1 != (int)a) && (PrefDir2 != (int)a) && (PrefDir3 != (int)a))
13106  {
13107  throw Exception("CheckPrefDir4MultiMap Error - MapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
13108  (AnsiString)CheckElement.VLoc + " Map values=" + (AnsiString)PrefDir0 + ", " + (AnsiString)PrefDir1 + ", " + (AnsiString)PrefDir2 + ", " +
13109  (AnsiString)PrefDir3 + " PrefDirVectorPos value=" + (AnsiString)a + " Caller=" + (AnsiString)Caller);
13110  }
13111  }
13112  if(PrefDirVector.size() != PrefDir4MultiMap.size())
13113  {
13114  throw Exception("CheckPrefDir4MultiMap Error - Map Size=" + (AnsiString)PrefDirVector.size() + " PrefDirVectorSize=" + (AnsiString)PrefDirVector.size()
13115  + " Caller=" + (AnsiString)Caller);
13116  }
13117  Utilities->CallLogPop(180);
13118 }
13119 
13120 // ---------------------------------------------------------------------------
13121 
13122 void TOnePrefDir::GetVectorPositionsFromPrefDir4MultiMap(int Caller, int HLoc, int VLoc, bool &FoundFlag, int &PrefDirPos0, int &PrefDirPos1, int &PrefDirPos2,
13123  int &PrefDirPos3)
13124 /*
13125  There are up to four elements at each H & V position in the PrefDirVector - two directions per track, and up to
13126  two tracks for 4-entry elements. This function retrieves all elements that are present at a give H & V
13127  position. FoundFlag indicates whether any or none have been found, and PrefDirPos0, 1, 2 & 3 contain
13128  the PrefDirVector positions, or -1 if not present. The elements are always found in order, such that
13129  if there is only one it will be in PrefDirPos0, if two they will be in PrefDirPos0 and PrefDirPos1 and so on.
13130 */
13131 {
13132  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionsFromPrefDir4MultiMap," + AnsiString(HLoc) + "," +
13133  AnsiString(VLoc));
13134  THVPair PrefDirMapKeyPair;
13135 
13136  PrefDirPos0 = -1;
13137  PrefDirPos1 = -1;
13138  PrefDirPos2 = -1;
13139  PrefDirPos3 = -1;
13140  FoundFlag = false;
13141  PrefDirMapKeyPair.first = HLoc;
13142  PrefDirMapKeyPair.second = VLoc;
13143  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
13144 
13145  ItPair = PrefDir4MultiMap.equal_range(PrefDirMapKeyPair);
13146  if(ItPair.first == ItPair.second) //none found
13147  {
13148  Utilities->CallLogPop(181);
13149  return;
13150  }
13151  else
13152  {
13153  FoundFlag = true;
13154  PrefDirPos0 = ItPair.first->second;
13155  ItPair.first++;
13156  if(ItPair.first == ItPair.second)
13157  {
13158  Utilities->CallLogPop(182); //only one found
13159  return;
13160  }
13161  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
13162  {
13163  PrefDirPos1 = ItPair.first->second;
13164  }
13165  ItPair.first++;
13166  if(ItPair.first == ItPair.second)
13167  {
13168  Utilities->CallLogPop(183); //2 found
13169  return;
13170  }
13171  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
13172  {
13173  PrefDirPos2 = ItPair.first->second;
13174  }
13175  ItPair.first++;
13176  if(ItPair.first == ItPair.second)
13177  {
13178  Utilities->CallLogPop(184); //3 found
13179  return;
13180  }
13181  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
13182  {
13183  PrefDirPos3 = ItPair.first->second; //4 found
13184  }
13185  }
13186  Utilities->CallLogPop(185);
13187 }
13188 
13189 // ---------------------------------------------------------------------------
13190 
13191 bool TOnePrefDir::FindLinkingPrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
13192 {
13193  // Finds a pref dir element that links to another element at given vector number and link number & position, returns true if found with linked
13194  // vector number, true if buffer or continuation with link at blank end & linked vector number = -1, or false if not found with vector number == -1
13195  try
13196  {
13197  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindLinkingPrefDir," + AnsiString(PrefDirVectorNumber)
13198  + "," + AnsiString(LinkNumberPos));
13199  bool FoundFlag;
13200  int PD0, PD1, PD2, PD3;
13201  if(PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos] > -1)
13202  {
13203  GetVectorPositionsFromPrefDir4MultiMap(14, Track->TrackElementAt(1021, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).HLoc,
13204  Track->TrackElementAt(1022, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).VLoc, FoundFlag,
13205  PD0, PD1, PD2, PD3);
13206  if(!FoundFlag)
13207  {
13208  Utilities->CallLogPop(2282);
13209  return(false);
13210  }
13211  if((PrefDirVector.at(PrefDirVectorNumber).TrackType == GapJump) && (LinkNumberPos == 0)) //0 is the gap position
13212  {
13213  if(PD0 > -1)
13214  {
13215  if(PrefDirVector.at(PD0).TrackType == GapJump) //links to a gap and there is a pref dir set on it, doesn't matter about the link position
13216  {
13217  LinkedPrefDirVectorNumber = PD0;
13218  Utilities->CallLogPop(2283);
13219  return(true);
13220  }
13221  }
13222  if(PD1 > -1)
13223  {
13224  if(PrefDirVector.at(PD1).TrackType == GapJump) //can only be PD0 or PD1 for a gap
13225  {
13226  LinkedPrefDirVectorNumber = PD1;
13227  Utilities->CallLogPop(2284);
13228  return(true);
13229  }
13230  }
13231  }
13232  if(PD0 > -1)
13233  {
13234  if((PrefDirVector.at(PD0).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD0).XLink == (10 - LinkNumber)))
13235  {
13236  LinkedPrefDirVectorNumber = PD0;
13237  Utilities->CallLogPop(2285);
13238  return(true);
13239  }
13240  }
13241  if(PD1 > -1)
13242  {
13243  if((PrefDirVector.at(PD1).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD1).XLink == (10 - LinkNumber)))
13244  {
13245  LinkedPrefDirVectorNumber = PD1;
13246  Utilities->CallLogPop(2286);
13247  return(true);
13248  }
13249  }
13250  if(PD2 > -1)
13251  {
13252  if((PrefDirVector.at(PD2).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD2).XLink == (10 - LinkNumber)))
13253  {
13254  LinkedPrefDirVectorNumber = PD2;
13255  Utilities->CallLogPop(2287);
13256  return(true);
13257  }
13258  }
13259  if(PD3 > -1)
13260  {
13261  if((PrefDirVector.at(PD3).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD3).XLink == (10 - LinkNumber)))
13262  {
13263  LinkedPrefDirVectorNumber = PD3;
13264  Utilities->CallLogPop(2288);
13265  return(true);
13266  }
13267  }
13268  LinkedPrefDirVectorNumber = -1;
13269  Utilities->CallLogPop(2289);
13270  return(false);
13271  }
13272  else //buffer or continuation, no link at position 0 but not a failure
13273  {
13274  LinkedPrefDirVectorNumber = -1;
13275  Utilities->CallLogPop(2290);
13276  return(true);
13277  }
13278  }
13279  catch(const Exception &e) //non error catch
13280  {
13281  LinkedPrefDirVectorNumber = -1;
13282  Utilities->CallLogPop(2291);
13283  return(false);
13284  }
13285 }
13286 
13287 // ---------------------------------------------------------------------------
13288 
13290 {
13291  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BiDirectionalPrefDir");
13292  bool FoundFlag; //not used
13293  int PD0, PD1, PD2, PD3;
13294  //recover all PDs at the H & V of PDPtr
13295  GetVectorPositionsFromPrefDir4MultiMap(15, PDPtr->first.first, PDPtr->first.second, FoundFlag, PD0, PD1, PD2, PD3);
13296 
13297  int ELink = PrefDirVector.at(PDPtr->second).GetELink();
13298  int XLink = PrefDirVector.at(PDPtr->second).GetXLink();
13299 
13300  if(PD0 > -1) //ok if PDPtr->second == PD0 as won't find a match, same for others
13301  {
13302  if((PrefDirVector.at(PD0).GetELink() == XLink) && (PrefDirVector.at(PD0).GetXLink() == ELink))
13303  {
13304  Utilities->CallLogPop(2292);
13305  return(true);
13306  }
13307  }
13308  if(PD1 > -1)
13309  {
13310  if((PrefDirVector.at(PD1).GetELink() == XLink) && (PrefDirVector.at(PD1).GetXLink() == ELink))
13311  {
13312  Utilities->CallLogPop(2293);
13313  return(true);
13314  }
13315  }
13316  if(PD2 > -1)
13317  {
13318  if((PrefDirVector.at(PD2).GetELink() == XLink) && (PrefDirVector.at(PD2).GetXLink() == ELink))
13319  {
13320  Utilities->CallLogPop(2294);
13321  return(true);
13322  }
13323  }
13324  if(PD3 > -1)
13325  {
13326  if((PrefDirVector.at(PD3).GetELink() == XLink) && (PrefDirVector.at(PD3).GetXLink() == ELink))
13327  {
13328  Utilities->CallLogPop(2295);
13329  return(true);
13330  }
13331  }
13332  Utilities->CallLogPop(2296);
13333  return(false);
13334 }
13335 
13336 // ---------------------------------------------------------------------------
13337 
13338 void TOnePrefDir::StorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
13339 /*
13340  LoadPrefDirElement is stored in both the PrefDirVector and in PrefDir4MultiMap.
13341 */
13342 {
13343  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StorePrefDirElement," + LoadPrefDirElement.LogPrefDir());
13344  PrefDirVector.push_back(LoadPrefDirElement);
13345  THVPair PrefDir4MultiMapKeyPair;
13346  TPrefDir4MultiMapEntry PrefDir4MultiMapEntry;
13347 
13348  PrefDir4MultiMapKeyPair.first = LoadPrefDirElement.HLoc;
13349  PrefDir4MultiMapKeyPair.second = LoadPrefDirElement.VLoc;
13350  PrefDir4MultiMapEntry.first = PrefDir4MultiMapKeyPair;
13351  PrefDir4MultiMapEntry.second = LastElementNumber(68);
13352  PrefDir4MultiMap.insert(PrefDir4MultiMapEntry);
13353 // CheckPrefDir4MultiMap(1);Drop here as takes too long - call it by each calling function
13354  Utilities->CallLogPop(186);
13355 }
13356 
13357 // ---------------------------------------------------------------------------
13358 
13359 void TOnePrefDir::ErasePrefDirElementAt(int Caller, int PrefDirVectorPosition)
13360 /*
13361  Erase a single element from PrefDirVector and 4MultiMap, decrementing the remaining PrefDirElementNumbers in
13362  4MultiMap if they are greater than the erased value.
13363 */
13364 {
13365  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ErasePrefDirElementAt," + AnsiString(PrefDirVectorPosition));
13366  bool FoundFlag;
13367 
13368  if(!PrefDirVector.empty())
13369  {
13370  TPrefDir4MultiMapIterator EraseIt = GetExactMatchFrom4MultiMap(0, PrefDirVectorPosition, FoundFlag);
13371  if(!FoundFlag)
13372  {
13373  throw Exception("Failed to find PrefDir4MultiMap erase element");
13374  }
13375  PrefDirVector.erase(PrefDirVector.begin() + PrefDirVectorPosition);
13376  PrefDir4MultiMap.erase(EraseIt);
13377  DecrementPrefDirElementNumbersInPrefDir4MultiMap(0, PrefDirVectorPosition);
13379  }
13380  Utilities->CallLogPop(187);
13381 }
13382 
13383 // ---------------------------------------------------------------------------
13384 
13385 void TOnePrefDir::DecrementPrefDirElementNumbersInPrefDir4MultiMap(int Caller, unsigned int ErasedElementNumber)
13386 /*
13387  Called after ErasePrefDirElementAt(int PrefDirVectorPosition) to decrement the remaining PrefDirElementNumbers in
13388  4MultiMap if they are greater than the erased value.
13389 */
13390 {
13391  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementPrefDirElementNumbersInPrefDir4MultiMap," +
13392  AnsiString(ErasedElementNumber));
13393  if(!PrefDir4MultiMap.empty())
13394  {
13395  for(TPrefDir4MultiMapIterator MapPtr = PrefDir4MultiMap.begin(); MapPtr != PrefDir4MultiMap.end(); MapPtr++)
13396  {
13397  if(MapPtr->second > ErasedElementNumber)
13398  {
13399  MapPtr->second--;
13400  }
13401  }
13402  }
13403  Utilities->CallLogPop(1450);
13404 }
13405 
13406 // ---------------------------------------------------------------------------
13407 
13408 TOnePrefDir::TPrefDir4MultiMapIterator TOnePrefDir::GetExactMatchFrom4MultiMap(int Caller, unsigned int PrefDirVectorPosition, bool &FoundFlag)
13409 /*
13410  Retrieves a PrefDir4MultiMap iterator to the PrefDir element at PrefDirVectorPosition. Used during
13411  ErasePrefDirElementAt(int PrefDirVectorPosition) to erase the relevant element in the multimap. If
13412  nothing is found this is an error but the error message is given in the calling function.
13413 */
13414 {
13415  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetExactMatchFrom4MultiMap," + AnsiString(PrefDirVectorPosition));
13416  FoundFlag = false;
13417  if(PrefDirVectorPosition >= PrefDirVector.size())
13418  {
13419  throw Exception("PrefDirVectorPosition out of range");
13420  }
13421  TPrefDirElement PrefDirElement = GetFixedPrefDirElementAt(14, PrefDirVectorPosition);
13422  THVPair PrefDir4MultiMapKeyPair;
13423 
13424  PrefDir4MultiMapKeyPair.first = PrefDirElement.HLoc;
13425  PrefDir4MultiMapKeyPair.second = PrefDirElement.VLoc;
13426  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
13427 
13428  ItPair = PrefDir4MultiMap.equal_range(PrefDir4MultiMapKeyPair);
13429  if(ItPair.first == ItPair.second)
13430  {
13431  Utilities->CallLogPop(188);
13432  return(ItPair.first); // nothing found but have to return an iterator, FoundFlag indicates nothing found
13433  }
13434  else
13435  {
13436  if(ItPair.first->second == PrefDirVectorPosition)
13437  {
13438  FoundFlag = true;
13439  Utilities->CallLogPop(189);
13440  return(ItPair.first);
13441  }
13442  ItPair.first++;
13443  if(ItPair.first == ItPair.second)
13444  {
13445  Utilities->CallLogPop(190);
13446  return(ItPair.first); // nothing found
13447  }
13448  if(ItPair.first->second == PrefDirVectorPosition)
13449  {
13450  FoundFlag = true;
13451  Utilities->CallLogPop(191);
13452  return(ItPair.first);
13453  }
13454  ItPair.first++;
13455  if(ItPair.first == ItPair.second)
13456  {
13457  Utilities->CallLogPop(192);
13458  return(ItPair.first); // nothing found
13459  }
13460  if(ItPair.first->second == PrefDirVectorPosition)
13461  {
13462  FoundFlag = true;
13463  Utilities->CallLogPop(193);
13464  return(ItPair.first);
13465  }
13466  ItPair.first++;
13467  if(ItPair.first == ItPair.second)
13468  {
13469  Utilities->CallLogPop(194);
13470  return(ItPair.first); // nothing found
13471  }
13472  if(ItPair.first->second == PrefDirVectorPosition)
13473  {
13474  FoundFlag = true;
13475  Utilities->CallLogPop(195);
13476  return(ItPair.first);
13477  }
13478  }
13479  Utilities->CallLogPop(196);
13480  return(ItPair.first); // nothing found
13481 }
13482 
13483 // ---------------------------------------------------------------------------
13484 
13485 int TOnePrefDir::GetOnePrefDirPosition(int Caller, int HLoc, int VLoc)
13486 /*
13487  Although there may be up to four entries at one H & V position this function gets just one. It is
13488  used in EraseFromPrefDirVectorAnd4MultiMap by being called as many times as there are PrefDir elements
13489  at H & V.
13490 */
13491 {
13492  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetOnePrefDirPosition," + AnsiString(HLoc) + "," + AnsiString(VLoc));
13493  THVPair PrefDir4MultiMapKeyPair;
13494 
13495  PrefDir4MultiMapKeyPair.first = HLoc;
13496  PrefDir4MultiMapKeyPair.second = VLoc;
13497  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
13498 
13499  ItPair = PrefDir4MultiMap.equal_range(PrefDir4MultiMapKeyPair);
13500  if(ItPair.first == ItPair.second) // nothing found
13501  {
13502  Utilities->CallLogPop(197);
13503  return(-1);
13504  }
13505  else
13506  {
13507  Utilities->CallLogPop(198);
13508  return(ItPair.first->second);
13509  }
13510 }
13511 
13512 // ---------------------------------------------------------------------------
13513 
13514 void TOnePrefDir::RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
13515 {
13516  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RealignAfterTrackErase," + AnsiString(ErasedTrackVectorPosition));
13517  bool ErasedFlag = false;
13518 
13519  if(ErasedTrackVectorPosition > -1) // should be in calling function but include here as a safeguard
13520  {
13521  if(PrefDirSize() == 0)
13522  {
13523  Utilities->CallLogPop(1511);
13524  return;
13525  }
13526  for(int x = (PrefDirSize() - 1); x >= 0; x--) // reverse because of erase
13527  {
13528  ErasedFlag = false;
13529  // use 'else' to ensure don't try to access an erased element
13530  if(PrefDirVector.at(x).TrackVectorPosition == ErasedTrackVectorPosition)
13531  {
13532  ErasePrefDirElementAt(11, x);
13533  ErasedFlag = true;
13534  }
13535  else if(PrefDirVector.at(x).Conn[0] == ErasedTrackVectorPosition)
13536  {
13537  ErasePrefDirElementAt(12, x);
13538  ErasedFlag = true;
13539  }
13540  else if(PrefDirVector.at(x).Conn[1] == ErasedTrackVectorPosition)
13541  {
13542  ErasePrefDirElementAt(13, x);
13543  ErasedFlag = true;
13544  }
13545  else if(PrefDirVector.at(x).Conn[2] == ErasedTrackVectorPosition)
13546  {
13547  ErasePrefDirElementAt(9, x);
13548  ErasedFlag = true;
13549  }
13550  else if(PrefDirVector.at(x).Conn[3] == ErasedTrackVectorPosition)
13551  {
13552  ErasePrefDirElementAt(10, x);
13553  ErasedFlag = true;
13554  }
13555  if(!ErasedFlag)
13556  {
13557  // don't use 'else' here as may be more than one that need decrementing
13558  if(PrefDirVector.at(x).TrackVectorPosition > ErasedTrackVectorPosition)
13559  {
13560  PrefDirVector.at(x).TrackVectorPosition--;
13561  }
13562  if(PrefDirVector.at(x).Conn[0] > ErasedTrackVectorPosition)
13563  {
13564  PrefDirVector.at(x).Conn[0]--;
13565  }
13566  if(PrefDirVector.at(x).Conn[1] > ErasedTrackVectorPosition)
13567  {
13568  PrefDirVector.at(x).Conn[1]--;
13569  }
13570  if(PrefDirVector.at(x).Conn[2] > ErasedTrackVectorPosition)
13571  {
13572  PrefDirVector.at(x).Conn[2]--;
13573  }
13574  if(PrefDirVector.at(x).Conn[3] > ErasedTrackVectorPosition)
13575  {
13576  PrefDirVector.at(x).Conn[3]--;
13577  }
13578  }
13579  }
13580  }
13581  Utilities->CallLogPop(1434);
13582 }
13583 
13584 // ---------------------------------------------------------------------------
13585 
13586 void TOnePrefDir::CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
13587 {
13588  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CalcDistanceAndSpeed");
13589  OverallDistance = 0;
13590  OverallSpeedLimit = 0;
13591  LeadingPointsAtLastElement = false;
13592  if(PrefDirSize() == 0) // shouldn't be empty when this called
13593  {
13594  Utilities->CallLogPop(1491);
13595  return;
13596  }
13597  if((LastElementPtr(21)->TrackType == Points) && (LastElementPtr(22)->ELinkPos != 1) && (LastElementPtr(23)->ELinkPos != 3))
13598  {
13599  LeadingPointsAtLastElement = true;
13600  Utilities->CallLogPop(1492);
13601  return;
13602  }
13603  for(unsigned int x = 0; x < PrefDirSize(); x++)
13604  {
13605  TPrefDirElement PrefDirElement = GetFixedPrefDirElementAt(166, x);
13606  if((PrefDirElement.GetELinkPos() > 1) || (PrefDirElement.GetXLinkPos() > 1)) // 'or' because points may have one == 0 & other == 3
13607  {
13608  OverallDistance += PrefDirElement.Length23;
13609  if(OverallSpeedLimit != -1) // if set to -1 there are mixed speed limits
13610  {
13611  if(x == 0)
13612  {
13613  OverallSpeedLimit = PrefDirElement.SpeedLimit23;
13614  }
13615  else
13616  {
13617  if(OverallSpeedLimit != PrefDirElement.SpeedLimit23)
13618  {
13619  OverallSpeedLimit = -1;
13620  }
13621  }
13622  }
13623  }
13624  else
13625  {
13626  OverallDistance += PrefDirElement.Length01;
13627  if(OverallSpeedLimit != -1) // if set to -1 there are mixed speed limits
13628  {
13629  if(x == 0)
13630  {
13631  OverallSpeedLimit = PrefDirElement.SpeedLimit01;
13632  }
13633  else
13634  {
13635  if(OverallSpeedLimit != PrefDirElement.SpeedLimit01)
13636  {
13637  OverallSpeedLimit = -1;
13638  }
13639  }
13640  }
13641  }
13642  }
13643  Utilities->CallLogPop(1529);
13644 }
13645 
13646 // ---------------------------------------------------------------------------
13647 
13648 void TOnePrefDir::WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
13649 {
13650  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WritePrefDirToImage");
13651  if(PrefDirSize() == 0)
13652  {
13653  Utilities->CallLogPop(1564);
13654  return;
13655  }
13656  int H, V, HLoc, VLoc, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
13657  bool FoundFlag;
13659  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
13660 
13661  while(MMIT != PrefDir4MultiMap.end())
13662  {
13663  HLoc = MMIT->first.first;
13664  VLoc = MMIT->first.second;
13665  GetVectorPositionsFromPrefDir4MultiMap(7, HLoc, VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
13666  H = HLoc - Track->GetHLocMin();
13667  V = VLoc - Track->GetVLocMin();
13668  // always found in order, any missing have PrefDirPosx == -1
13669  if(PrefDirPos0 > -1)
13670  {
13671  PrefDirElement0 = GetFixedPrefDirElementAt(174, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
13672  }
13673  if(PrefDirPos1 > -1)
13674  {
13675  PrefDirElement1 = GetFixedPrefDirElementAt(175, PrefDirPos1);
13676  }
13677  if(PrefDirPos2 > -1)
13678  {
13679  PrefDirElement2 = GetFixedPrefDirElementAt(176, PrefDirPos2);
13680  }
13681  if(PrefDirPos3 > -1)
13682  {
13683  PrefDirElement3 = GetFixedPrefDirElementAt(177, PrefDirPos3);
13684  }
13685  if(PrefDirPos3 > -1) // 4 found, mark all PrefDirs bidirectional (operator == ensures no duplicates in ConsolidatePrefDirs)
13686  {
13687  // need to plot all 4 in order to obtain all the direction graphics
13688  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13689  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13690  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13691  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13692  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
13693  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
13694  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement3.GetRouteGraphicPtr(false, true)); // green
13695  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement3.GetDirectionRouteGraphicPtr(false, true)); // green
13696  MMIT++;
13697  MMIT++;
13698  MMIT++;
13699  MMIT++;
13700  }
13701  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
13702  {
13703  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
13704  {
13705  // 0 & 1 constitute the bidirectional PrefDir
13706  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13707  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13708  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13709  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13710  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, false)); // red
13711  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, false)); // red
13712  MMIT++;
13713  MMIT++;
13714  MMIT++;
13715  }
13716  else if(PrefDirElement0.EXNumber == PrefDirElement2.EXNumber)
13717  {
13718  // 0 & 2 constitute the bidirectional PrefDir
13719  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13720  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13721  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
13722  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
13723  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
13724  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
13725  MMIT++;
13726  MMIT++;
13727  MMIT++;
13728  }
13729  else
13730  {
13731  // 1 & 2 constitute the bidirectional PrefDir
13732  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13733  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13734  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
13735  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
13736  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
13737  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
13738  MMIT++;
13739  MMIT++;
13740  MMIT++;
13741  }
13742  }
13743  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
13744  {
13745  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
13746  {
13747  // 0 & 1 constitute the bidirectional PrefDir
13748  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13749  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13750  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13751  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13752  MMIT++;
13753  MMIT++;
13754  }
13755  else
13756  {
13757  // 2 unidirectional PrefDirs
13758  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
13759  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
13760  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
13761  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
13762  MMIT++;
13763  MMIT++;
13764  }
13765  }
13766  else if(PrefDirPos0 > -1) // 1 found, must be unidirectional
13767  {
13768  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
13769  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
13770  MMIT++;
13771  }
13772  }
13773  Utilities->CallLogPop(1565);
13774 }
13775 
13776 // ---------------------------------------------------------------------------
13777 
13778 bool TOnePrefDir::PresetAutoRouteElementValid(int Caller, TPrefDirElement ElementIn, int EntryPos) // added at v1.2.0
13779 /*
13780  Checks ElementIn and returns true only if a single prefdir set at that H&V, with EntryPos giving entry position, not points, crossovers,
13781  level crossing, signals with wrong direction set, or buffers.
13782 */
13783 {
13784  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PresetAutoRouteElementValid");
13785  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
13786  bool FoundFlag;
13788  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
13789 
13790  if((ElementIn.TrackType == Points) || (ElementIn.TrackType == Crossover) || (ElementIn.TrackType == Buffers) || (Track->IsLCAtHV(49, ElementIn.HLoc,
13791  ElementIn.VLoc)))
13792  {
13793  Utilities->CallLogPop(1982);
13794  return(false);
13795  }
13796  if((ElementIn.TrackType == SignalPost) && (ElementIn.Config[EntryPos] == Signal)) // Signal is at exit end
13797  {
13798  Utilities->CallLogPop(1983);
13799  return(false);
13800  }
13801  if((ElementIn.TrackType == SignalPost) && (ElementIn.SigAspect == TTrackElement::GroundSignal))
13802  {
13803  Utilities->CallLogPop(1995);
13804  return(false);
13805  }
13806 // Now check that there is only a single prefdir set
13807  GetVectorPositionsFromPrefDir4MultiMap(8, ElementIn.HLoc, ElementIn.VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
13808 // always found in order, any missing have PrefDirPosx == -1
13809  if(PrefDirPos0 > -1)
13810  {
13811  PrefDirElement0 = GetFixedPrefDirElementAt(213, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
13812  }
13813  if(PrefDirPos1 > -1)
13814  {
13815  PrefDirElement1 = GetFixedPrefDirElementAt(214, PrefDirPos1);
13816  }
13817  if(PrefDirPos2 > -1)
13818  {
13819  PrefDirElement2 = GetFixedPrefDirElementAt(215, PrefDirPos2);
13820  }
13821  if(PrefDirPos3 > -1)
13822  {
13823  PrefDirElement3 = GetFixedPrefDirElementAt(216, PrefDirPos3);
13824  }
13825  if(PrefDirPos3 > -1) // 4 found, all bidirectional
13826  {
13827  Utilities->CallLogPop(1984);
13828  return(false);
13829  }
13830  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
13831  {
13832  if((PrefDirElement0.XLinkPos == EntryPos) || (PrefDirElement1.XLinkPos == EntryPos) || (PrefDirElement2.XLinkPos == EntryPos))
13833  {
13834  Utilities->CallLogPop(1985);
13835  return(false);
13836  }
13837  else
13838  {
13839  Utilities->CallLogPop(1986);
13840  return(true);
13841  }
13842  }
13843  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
13844  {
13845  if((PrefDirElement0.XLinkPos == EntryPos) || (PrefDirElement1.XLinkPos == EntryPos))
13846  {
13847  Utilities->CallLogPop(1987);
13848  return(false);
13849  }
13850  else
13851  {
13852  Utilities->CallLogPop(1988);
13853  return(true);
13854  }
13855  }
13856  else if(PrefDirPos0 > -1) // one found, make sure in correct direction
13857  {
13858  if(PrefDirElement0.XLinkPos == EntryPos)
13859  {
13860  Utilities->CallLogPop(1989);
13861  return(false);
13862  }
13863  else
13864  {
13865  Utilities->CallLogPop(1990);
13866  return(true);
13867  }
13868  }
13869  else
13870  {
13871  Utilities->CallLogPop(1991);
13872  return(false); // none found
13873  }
13874 }
13875 
13876 // ---------------------------------------------------------------------------
13877 
13879 {
13880 /* //Added at v2.1.0
13881  Called by GetStartAndEndPrefDirElements, which in turn is called by PresetAutoSigRoutesButtonClick. Checks for a diagonal link in
13882  the autosigsroute being fouled by an adjacent track with a corresponding link that meets at the diagonal link, and if it is it
13883  returns true and prevents the route being set. Note that adjacent track consisting of buffers, gaps and continuations at the
13884  diagonal link are also excluded though they need not be, but it makes the check code simpler and such adjacent track is untidy
13885  and can be modelled better anyway.
13886 
13887  Enter with PrefDirElement whose XLink is to be checked for track that fouls a diagonal.
13888  If XLink is anything but 1,3,7 or 9 return false - no fouling as not a diagonal.
13889  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
13890  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
13891  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
13892  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
13893 */
13894  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PresetAutoRouteDiagonalFouledByTrack," + ElementIn.HLoc + "," +
13895  ElementIn.VLoc + "," + XLink);
13896  int TrackVecPos;
13897  bool TrackFoundFlag;
13898  TTrackElement TempTrackElement;
13899 
13900  if((XLink == 2) || (XLink == 4) || (XLink == 6) || (XLink == 8))
13901  {
13902  Utilities->CallLogPop(2047);
13903  return(false);
13904  }
13905 // for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
13906  if(XLink == 1)
13907  {
13908  TrackVecPos = Track->GetVectorPositionFromTrackMap(48, ElementIn.HLoc - 1, ElementIn.VLoc, TrackFoundFlag);
13909  if(TrackFoundFlag)
13910  {
13911  TempTrackElement = Track->TrackElementAt(898, TrackVecPos);
13912  if((TempTrackElement.Link[0] == 3) || (TempTrackElement.Link[1] == 3) || (TempTrackElement.Link[2] == 3) || (TempTrackElement.Link[3] == 3))
13913  {
13914  Utilities->CallLogPop(2048);
13915  return(true);
13916  }
13917  }
13918  TrackVecPos = Track->GetVectorPositionFromTrackMap(49, ElementIn.HLoc, ElementIn.VLoc - 1, TrackFoundFlag);
13919  if(TrackFoundFlag)
13920  {
13921  TempTrackElement = Track->TrackElementAt(899, TrackVecPos);
13922  if((TempTrackElement.Link[0] == 7) || (TempTrackElement.Link[1] == 7) || (TempTrackElement.Link[2] == 7) || (TempTrackElement.Link[3] == 7))
13923  {
13924  Utilities->CallLogPop(2049);
13925  return(true);
13926  }
13927  }
13928  }
13929 // for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
13930  if(XLink == 3)
13931  {
13932  TrackVecPos = Track->GetVectorPositionFromTrackMap(50, ElementIn.HLoc + 1, ElementIn.VLoc, TrackFoundFlag);
13933  if(TrackFoundFlag)
13934  {
13935  TempTrackElement = Track->TrackElementAt(900, TrackVecPos);
13936  if((TempTrackElement.Link[0] == 1) || (TempTrackElement.Link[1] == 1) || (TempTrackElement.Link[2] == 1) || (TempTrackElement.Link[3] == 1))
13937  {
13938  Utilities->CallLogPop(2050);
13939  return(true);
13940  }
13941  }
13942  TrackVecPos = Track->GetVectorPositionFromTrackMap(51, ElementIn.HLoc, ElementIn.VLoc - 1, TrackFoundFlag);
13943  if(TrackFoundFlag)
13944  {
13945  TempTrackElement = Track->TrackElementAt(901, TrackVecPos);
13946  if((TempTrackElement.Link[0] == 9) || (TempTrackElement.Link[1] == 9) || (TempTrackElement.Link[2] == 9) || (TempTrackElement.Link[3] == 9))
13947  {
13948  Utilities->CallLogPop(2051);
13949  return(true);
13950  }
13951  }
13952  }
13953 // for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
13954  if(XLink == 7)
13955  {
13956  TrackVecPos = Track->GetVectorPositionFromTrackMap(52, ElementIn.HLoc - 1, ElementIn.VLoc, TrackFoundFlag);
13957  if(TrackFoundFlag)
13958  {
13959  TempTrackElement = Track->TrackElementAt(902, TrackVecPos);
13960  if((TempTrackElement.Link[0] == 9) || (TempTrackElement.Link[1] == 9) || (TempTrackElement.Link[2] == 9) || (TempTrackElement.Link[3] == 9))
13961  {
13962  Utilities->CallLogPop(2052);
13963  return(true);
13964  }
13965  }
13966  TrackVecPos = Track->GetVectorPositionFromTrackMap(53, ElementIn.HLoc, ElementIn.VLoc + 1, TrackFoundFlag);
13967  if(TrackFoundFlag)
13968  {
13969  TempTrackElement = Track->TrackElementAt(903, TrackVecPos);
13970  if((TempTrackElement.Link[0] == 1) || (TempTrackElement.Link[1] == 1) || (TempTrackElement.Link[2] == 1) || (TempTrackElement.Link[3] == 1))
13971  {
13972  Utilities->CallLogPop(2053);
13973  return(true);
13974  }
13975  }
13976  }
13977 // for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
13978  if(XLink == 9)
13979  {
13980  TrackVecPos = Track->GetVectorPositionFromTrackMap(54, ElementIn.HLoc + 1, ElementIn.VLoc, TrackFoundFlag);
13981  if(TrackFoundFlag)
13982  {
13983  TempTrackElement = Track->TrackElementAt(904, TrackVecPos);
13984  if((TempTrackElement.Link[0] == 7) || (TempTrackElement.Link[1] == 7) || (TempTrackElement.Link[2] == 7) || (TempTrackElement.Link[3] == 7))
13985  {
13986  Utilities->CallLogPop(2054);
13987  return(true);
13988  }
13989  }
13990  TrackVecPos = Track->GetVectorPositionFromTrackMap(55, ElementIn.HLoc, ElementIn.VLoc + 1, TrackFoundFlag);
13991  if(TrackFoundFlag)
13992  {
13993  TempTrackElement = Track->TrackElementAt(905, TrackVecPos);
13994  if((TempTrackElement.Link[0] == 3) || (TempTrackElement.Link[1] == 3) || (TempTrackElement.Link[2] == 3) || (TempTrackElement.Link[3] == 3))
13995  {
13996  Utilities->CallLogPop(2055);
13997  return(true);
13998  }
13999  }
14000  }
14001  Utilities->CallLogPop(2056);
14002  return(false);
14003 }
14004 
14005 // ---------------------------------------------------------------------------
14006 
14007 bool TOnePrefDir::GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
14008 {
14009 /* Called by PresetAutoSigRoutesButtonClick in the Interface unit. LastIteratorValue gives the position in EveryPrefDir to start from. Search
14010  EveryPrefDir for continuations (facing inwards wrt pref dir) or non-ground signals in single direction pref dirs, and when find one track forwards
14011  to the next non-ground signal or continuation. If, before finding a valid signal or continuation find points, crossover, level crossing or buffers,
14012  or an element that is already in a route, stop tracking and continue with the search for another valid continuation or signal. When find a suitable
14013  pair, return the elements in StartElement and EndElement, and also the LastIteratorValue ready for the next call.
14014 */
14015  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetStartAndEndPrefDirElements," + AnsiString(LastIteratorValue));
14017  bool FoundFlag, ContFlag, FoundElements = false;
14018  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
14019  TPrefDirElement NextElement;
14020 
14021  for(PDVIt = (PrefDirVector.begin() + LastIteratorValue); PDVIt < PrefDirVector.end(); PDVIt++)
14022  {
14023  LastIteratorValue++;
14024  ContFlag = false;
14025  if((PDVIt->TrackType != SignalPost) && (PDVIt->TrackType != Continuation))
14026  {
14027  continue;
14028  }
14029  if((PDVIt->TrackType == SignalPost) && (PDVIt->SigAspect == TTrackElement::GroundSignal))
14030  {
14031  continue;
14032  }
14033 // if(AllRoutes::TrackIsInARoute(, PDVIt->TrackVectorPosition, PDVIt->EntryPos) continue; //already in a route - no, don't check start position as if a signal might well be at end of an existing route
14034  // found a potential route start point
14035  if(PresetAutoRouteDiagonalFouledByTrack(0, *PDVIt, PDVIt->XLink)) // Added at v2.1.0
14036  {
14037  continue;
14038  }
14039  if(PresetAutoRouteElementValid(0, *PDVIt, PDVIt->ELinkPos))
14040  {
14041  // check if continuation either in a route or with prefdir facing 'End' (OK if find it as EndElement, but not as StartElement)
14042  if(PDVIt->TrackType == Continuation)
14043  {
14044  if(AllRoutes->TrackIsInARoute(18, PDVIt->TrackVectorPosition, PDVIt->ELinkPos))
14045  {
14046  continue;
14047  }
14048  if(PDVIt->XLinkPos == 0) // position 0 is the continuation
14049  {
14050  continue;
14051  }
14052  }
14053  StartElement = *PDVIt;
14054 // in Glenn Mitchell's error log (14/04/13) the offending signal start position was 4680, problem was it linked to a point with pref dirs set on through track but signal linked to
14055  // diverging track on which there was no pref dir. See below for 2 required changes.
14056  }
14057  else
14058  {
14059  continue;
14060  }
14061  // now track along until find a signal or continuation, checking validity for each element
14062  int NextTrackVectorPosition = PDVIt->Conn[PDVIt->GetXLinkPos()];
14063  GetVectorPositionsFromPrefDir4MultiMap(9, Track->TrackElementAt(878, NextTrackVectorPosition).HLoc,
14064  Track->TrackElementAt(879, NextTrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14065  if(PrefDirPos0 == -1) // no continuing prefdir
14066  {
14067  continue;
14068  }
14069  bool NextElementFoundFlag = false;
14070  if(GetFixedPrefDirElementAt(217, PrefDirPos0).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
14071  {
14072  NextElement = GetFixedPrefDirElementAt(218, PrefDirPos0);
14073  NextElementFoundFlag = true;
14074  }
14075  if(PrefDirPos1 > -1)
14076  {
14077  if(GetFixedPrefDirElementAt(219, PrefDirPos1).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
14078  {
14079  NextElement = GetFixedPrefDirElementAt(220, PrefDirPos1);
14080  NextElementFoundFlag = true;
14081  }
14082  }
14083  if(PrefDirPos2 > -1)
14084  {
14085  if(GetFixedPrefDirElementAt(221, PrefDirPos2).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
14086  {
14087  NextElement = GetFixedPrefDirElementAt(222, PrefDirPos2);
14088  NextElementFoundFlag = true;
14089  }
14090  }
14091  if(PrefDirPos3 > -1)
14092  {
14093  if(GetFixedPrefDirElementAt(223, PrefDirPos3).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
14094  {
14095  NextElement = GetFixedPrefDirElementAt(224, PrefDirPos3);
14096  NextElementFoundFlag = true;
14097  }
14098  }
14099  if(!NextElementFoundFlag)
14100  {
14101  continue; // Modified for release 1.3.2 (sent as beta to John Phillipson initially)
14102 // throw(Exception("Failed to track prefdir in PresetAutoSigRoutesButtonClick (1)")); //[GM error 14/04/13] for next release change this to 'continue;' to quit from trying to find the auto route (don't need to throw an exception)
14103  }
14104  while(true)
14105  {
14106  // check validity
14107  if(PresetAutoRouteDiagonalFouledByTrack(1, NextElement, NextElement.XLink)) // Added at v2.1.0
14108  {
14109  ContFlag = true;
14110  break;
14111  }
14112  if(!PresetAutoRouteElementValid(1, NextElement, NextElement.ELinkPos))
14113  {
14114  ContFlag = true;
14115  break;
14116  }
14117  // check if in a route, providing not a signal, as a signal might be at the start of a route
14118  if(NextElement.TrackType != SignalPost)
14119  {
14120  if(AllRoutes->TrackIsInARoute(17, NextElement.TrackVectorPosition, NextElement.ELinkPos))
14121  {
14122  ContFlag = true;
14123  break;
14124  }
14125  }
14126  if((NextElement.TrackType == SignalPost) || (NextElement.TrackType == Continuation))
14127  // can't be a gound signal as would have failed the validity test
14128  {
14129  EndElement = NextElement;
14130  break;
14131  }
14132  // get the next element in the sequence
14133  NextTrackVectorPosition = NextElement.Conn[NextElement.GetXLinkPos()];
14134  GetVectorPositionsFromPrefDir4MultiMap(10, Track->TrackElementAt(880, NextTrackVectorPosition).HLoc,
14135  Track->TrackElementAt(881, NextTrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14136  if(PrefDirPos0 == -1) // no continuing prefdir
14137  {
14138  ContFlag = true;
14139  break;
14140  }
14141  if(GetFixedPrefDirElementAt(225, PrefDirPos0).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
14142  {
14143  NextElement = GetFixedPrefDirElementAt(226, PrefDirPos0);
14144  continue;
14145  }
14146  if(PrefDirPos1 > -1)
14147  {
14148  if(GetFixedPrefDirElementAt(227, PrefDirPos1).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
14149  {
14150  NextElement = GetFixedPrefDirElementAt(228, PrefDirPos1);
14151  continue;
14152  }
14153  }
14154  if(PrefDirPos2 > -1)
14155  {
14156  if(GetFixedPrefDirElementAt(229, PrefDirPos2).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
14157  {
14158  NextElement = GetFixedPrefDirElementAt(230, PrefDirPos2);
14159  continue;
14160  }
14161  }
14162  if(PrefDirPos3 > -1)
14163  {
14164  if(GetFixedPrefDirElementAt(231, PrefDirPos3).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
14165  {
14166  NextElement = GetFixedPrefDirElementAt(232, PrefDirPos3);
14167  continue;
14168  }
14169  }
14170  // had exception thrown here if NextElement not found, but could be a bridge where opposite track PrefDir set, in which case won't find it
14171  // found with Jonathan Kwok's DLR railway (17/11/12) where undertrack PrefDir not set just west of Poplar. Hence first test if element is a bridge
14172  // and if so set ContFlag to true & break (same as not finding PrefDir element at all). Modified at version 1.3.1
14173  // note that it's not NextElement that is to be examined but NextTrackVectorPosition, which can be found easily by using PrefDirPos0 (there will be a
14174  // PrefDirPos0 or would have exited earlier, and it doesn't matter that PrefDirPos0 isn't on the route in question because only the TrackType is needed)
14175  if(GetFixedPrefDirElementAt(243, PrefDirPos0).TrackType == Bridge)
14176  {
14177  ContFlag = true;
14178  break;
14179  }
14180  else
14181  {
14182  ContFlag = true; // Modified for release 1.3.2 (sent as beta to John Phillipson initially)
14183  // could drop the bridge test but keep it to show the change history
14184  break;
14185 // throw(Exception("Failed to track prefdir in PresetAutoSigRoutesButtonClick (2)")); //[GM error 14/04/13] for next release set ContFlag to true & break' to quit from trying to find the auto route (don't need to throw an exception)
14186  }
14187  }
14188  if(ContFlag)
14189  {
14190  continue;
14191  }
14192  // else have start and end elements set & all elements valid, so set up the route segment
14193  FoundElements = true;
14194  break;
14195  }
14196  if(FoundElements)
14197  {
14198  Utilities->CallLogPop(1992);
14199  return(true);
14200  }
14201  else
14202  {
14203  Utilities->CallLogPop(1993);
14204  return(false);
14205  }
14206 }
14207 
14208 // ---------------------------------------------------------------------------
14209 // TOneRoute
14210 // ---------------------------------------------------------------------------
14211 
14212 bool TOneRoute::GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool AutoSigsFlag)
14213 {
14214 /* General:
14215  The basis of all these route setting functions, preferred and non-preferred, is that a SearchVector is set up
14216  containing all the new elements to form the route. When complete, the SearchVector is converted into route
14217  elements, either as a new route, or an extension to an existing route. The AutoSigs flag determines whether the
14218  route will use automatic signals or not.
14219  For preferred and non-preferred routes, all new elements (as opposed to those already in existing routes) go
14220  into the SearchVector. For non-preferred routes, trackelements are selected that are not necessarily PrefDir
14221  elements, so additional work is needed to complete all their members before they are ready for conversion into
14222  a route - see SetRemainingSearchVectorValues. The call order is GetStart....; GetNext...,
14223  which includes the Search... function; [SetRemainingSearchVectorValues for non-preferred routes only], then
14224  ConvertAndAdd.......
14225 */
14226  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPreferredRouteStartElement," + AnsiString(HLoc) + "," +
14227  AnsiString(VLoc) + "," + AnsiString((short)AutoSigsFlag));
14228  ClearRoute();
14229  int TrackVectorPosition;
14230  TTrackElement TrackElement;
14231  TPrefDirElement FirstElement, LastElement;
14232 
14233  if(!(Track->FindNonPlatformMatch(7, HLoc, VLoc, TrackVectorPosition, TrackElement)))
14234  {
14235  Utilities->CallLogPop(199);
14236  return(false);
14237  }
14238  if(AutoSigsFlag && (TrackElement.TrackType == Buffers)) // added at v1.2.0
14239  {
14240  TrainController->StopTTClockMessage(80, "Can't create an automatic signal route from buffers");
14241  Utilities->CallLogPop(1996);
14242  return(false);
14243  }
14244  else if((TrackElement.TrackType != SignalPost) && (TrackElement.TrackType != Buffers) && (TrackElement.TrackType != Continuation))
14245  {
14246  TrainController->StopTTClockMessage(7, "Must select a valid signal, buffers or continuation");
14247  Utilities->CallLogPop(200);
14248  return(false);
14249  }
14250  if(Track->IsLCAtHV(18, HLoc, VLoc))
14251  {
14252  TrainController->StopTTClockMessage(73, "Can't start a route on a level crossing");
14253  Utilities->CallLogPop(1909);
14254  return(false);
14255  }
14256 // check if selected a train & disallow if so
14257  if(TrackElement.TrainIDOnElement > -1)
14258  {
14259  TrainController->StopTTClockMessage(9, "Can't start a route on a train");
14260  Utilities->CallLogPop(202);
14261  return(false);
14262  }
14263 // check if selected a locked route element & disallow (can only be a 2-track element so only need check XLinkPos values of 0 & 1
14264  TPrefDirElement PrefDirElement;
14265  int LockedVectorNumber;
14266 
14267  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(1, TrackVectorPosition, 0, PrefDirElement, LockedVectorNumber))
14268  {
14269  TrainController->StopTTClockMessage(10, "Can't start a route on a locked route");
14270  Utilities->CallLogPop(203);
14271  return(false);
14272  }
14273  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(2, TrackVectorPosition, 1, PrefDirElement, LockedVectorNumber))
14274  {
14275  TrainController->StopTTClockMessage(11, "Can't start a route on a locked route");
14276  Utilities->CallLogPop(204);
14277  return(false);
14278  }
14280  StartRoutePosition = TrackVectorPosition; // actual route start - may be element following StartRouteSelectPosition if select a
14281 // signal in an autosig route & follow with a non-autosig route
14282 
14283  TPrefDirElement BlankElement;
14284 
14285  StartElement1 = BlankElement;
14286  StartElement2 = BlankElement; //not used in this routine but used in GetNextPreferred.... though could probably dispense with it there
14287 // check it's in a PrefDir (could be 2 entries for two possible PrefDirs, can only select single track elements so can't have more than 2 PrefDirs)
14288  bool InPrefDirFlag = false;
14289 
14290  bool FoundFlag;
14291  int PrefDirPos0 = -1;
14292  int PrefDirPos1 = -1;
14293  int PrefDirPos2 = -1;
14294  int PrefDirPos3 = -1;
14295 
14297  Track->TrackElementAt(85, StartRoutePosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14298  int PrefDirVecPos[4] =
14299  {
14300  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
14301  };
14302 
14303  for(int x = 0; x < 4; x++)
14304  {
14305  int b = PrefDirVecPos[x];
14306  if(b > -1)
14307  {
14308  // only allow the appropriate exit route to be searched
14309  if(((TrackElement.TrackType == SignalPost) && (EveryPrefDir->GetFixedPrefDirElementAt(15, b).Config[EveryPrefDir->GetFixedPrefDirElementAt(16,
14310  b).XLinkPos] == Signal)) || ((TrackElement.TrackType == Buffers) && (EveryPrefDir->GetFixedPrefDirElementAt(17,
14311  b).Config[EveryPrefDir->GetFixedPrefDirElementAt(18, b).XLinkPos] == Connection)) ||
14312  ((TrackElement.TrackType == Continuation) && (EveryPrefDir->GetFixedPrefDirElementAt(19,
14313  b).Config[EveryPrefDir->GetFixedPrefDirElementAt(20, b).XLinkPos] == Connection)))
14314  {
14315  InPrefDirFlag = true;
14316  StartElement1 = EveryPrefDir->GetFixedPrefDirElementAt(21, b);
14317  if(AutoSigsFlag)
14318  {
14319  StartElement1.AutoSignals = true;
14320  }
14321  StartElement1.PrefDirRoute = true;
14322  }
14323  }
14324  }
14325 
14326  if(!InPrefDirFlag)
14327  {
14329  "Route and preferred direction mismatch. If no preferred direction then only red routes can be used. Green and blue route directions must correspond to the preferred direction.");
14330  Utilities->CallLogPop(205);
14331  return(false);
14332  }
14333 // look for exact match in a route first - can't be a bridge so can use a simple 'find'
14335  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(14, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
14336 
14337  if(DummyPair.first > -1) // if DummyPair exists then an error as start element can only be in one route (bridges not allowed)
14338  {
14339  throw Exception("Selection in two routes - should never happen!");
14340  }
14341  if(RoutePair.first > -1) // no need to examine DummyPair as start element can only be in one route (bridges not allowed)
14342  {
14343  if(RoutePair.second != AllRoutes->GetFixedRouteAt(1, RoutePair.first).PrefDirSize() - 1) // not last element in existing route so no good
14344  {
14345  TrainController->StopTTClockMessage(13, "Can't start a route within or at the start of an existing route");
14346  Utilities->CallLogPop(206);
14347  return(false);
14348  }
14349  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(2, RoutePair.first).GetFixedPrefDirElementAt(29, RoutePair.second);
14350  if(RouteElement.Conn[RouteElement.XLinkPos] < 0) // last element in existing route but nowhere to go!
14351  {
14352  TrainController->StopTTClockMessage(14, "No forward connection from this position");
14353  Utilities->CallLogPop(207);
14354  return(false);
14355  }
14356  if((RouteElement.Config[RouteElement.XLinkPos] != End) && (AllRoutes->TrackIsInARoute(9, RouteElement.Conn[RouteElement.XLinkPos],
14357  RouteElement.ConnLinkPos[RouteElement.XLinkPos])))
14358  // last element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
14359  {
14360  TrainController->StopTTClockMessage(15, "Can't start a route at an element that links forward into an existing route");
14361  Utilities->CallLogPop(208);
14362  return(false);
14363  }
14364  StartSelectionRouteID = IDInt(AllRoutes->GetFixedRouteAt(158, RoutePair.first).RouteID);
14366  AllRoutes->GetFixedRouteAt(4, RoutePair.first).PrefDirSize() - 1); // last element
14367  if(AutoSigsFlag)
14368  {
14369  StartElement1.AutoSignals = true;
14370  }
14371  StartElement1.PrefDirRoute = true;
14373  Utilities->CallLogPop(209);
14374  return(true); // all retained values (StartElement1 & maybe 2; StartRoutePosition) set
14375  }
14376 
14377  else // no route started
14378  {
14379 // check if selected position is adjacent to start or end of an existing route and disallow
14380  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
14381  {
14382  FirstElement = AllRoutes->GetFixedRouteAt(5, a).GetFixedPrefDirElementAt(31, 0);
14383  if((StartElement1.Conn[0] > -1) && (StartElement1.Conn[0] == FirstElement.TrackVectorPosition))
14384  {
14385  TrainController->StopTTClockMessage(16, "Can't make selection adjacent to start of another route");
14386  Utilities->CallLogPop(210);
14387  return(false);
14388  }
14389  if((StartElement1.Conn[1] > -1) && (StartElement1.Conn[1] == FirstElement.TrackVectorPosition))
14390  {
14391  TrainController->StopTTClockMessage(17, "Can't make selection adjacent to start of another route");
14392  Utilities->CallLogPop(211);
14393  return(false);
14394  }
14395  }
14396 
14397 // check if it's adjacent to end of an an existing route,
14398  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
14399  {
14401  if(LastElement.Conn[LastElement.XLinkPos] == StartRoutePosition)
14402  {
14403  TrainController->StopTTClockMessage(18, "Can't start a route adjacent to the end of an existing route");
14404  Utilities->CallLogPop(212);
14405  return(false);
14406  }
14407  }
14408  SearchVector.push_back(StartElement1);
14409  Utilities->CallLogPop(213);
14410  return(true);
14411  }
14412 }
14413 
14414 // ---------------------------------------------------------------------------
14415 
14416 bool TOneRoute::GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignals, bool AutoSigsFlag,
14417  IDInt &ReqPosRouteID, bool &PointsChanged)
14418 
14419 /*
14420  Return true if select valid next element, in which case the route is set & stored in SearchVector. Return false for an invalid next element.
14421 
14422  Declare integers EndPosition (the position used) and ReqPosRouteID to hold (when required) the existing route selected (for linking to an existing route),
14423  this being set to -1 for not used.
14424  Check if selection is a valid track element, cancel if not, if select original start element or if select buffers
14425  with AutoSigsFlag set - would have no way out and no way to cancel the route with a train at the buffers.
14426  Check correct type of element - signal/buffers/continuation.
14427  Fail if train on element, or if selection not in EveryPrefDir. Otherwise set EndElement1 & possibly also
14428  EndElement2 corresponding to the 2 possible PrefDir elements).
14429  Check if selection is first element in an existing route & if so set ReqPosRouteID, EndElement1, and set EndElement2 to
14430  blank as can only be one route at that element (can't select bridges). Fail if in a route & not at start, or at start but route
14431  linked forward to another route.
14432  Check & fail if adjacent to start or end of an existing route, or if select the route that selected at start (though earlier check
14433  for same position as start should cover this)
14434 
14435  If there's a StartSelectionRouteID then StartElement1 will be set to the last entry in the selected route so use
14436  SearchForPreferredRoute to search for the selected end element from this start element. If succeed then set the search vector
14437  graphics using SetRouteSearchVectorGraphics(AutoSigsFlag) & return true, for Interface to handle the flashing & time delay. After the
14438  delay completes the Interface flasher calls ConvertAndAddPreferredRouteSearchVector to add the new route to the AllRoutesVectorPtr.
14439  If the search fails then return false.
14440  If there isn't a StartSelectionRouteID then the starting element is not already in a route, so it will have been stored
14441  in the SearchVector to ensure it's entered as part of the new route.
14442  First check whether the selected element (either EndElement1 or 2) is adjacent to the starting position and if so set the route to go
14443  directly to it (as opposed to going round a long loop to get to it just because that XLinkPos happens to be chosen first. If not
14444  adjacent then first search on EndElement1, and if fail search on EndElement2 providing it's set. If succeed
14445  set the search vector graphics as above and return. If reach end of function then have failed to find a valid element,
14446  so return false, with an appropriate message if ConsecSignalsRoute set.
14447 */
14448 
14449 {
14450  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextPreferredRouteElement," + AnsiString(HLoc) + "," +
14451  AnsiString(VLoc) + "," + AnsiString((short)ConsecSignals) + "," + AnsiString((short)AutoSigsFlag));
14452  int EndPosition; // the position selected
14453 
14454  Track->LCFoundInAutoSigsRoute = false;
14456  TotalSearchCount = 0;
14457  ReqPosRouteID = IDInt(-1); // default value for not used
14458  TTrackElement TrackElement;
14459  TPrefDirElement EndElement1, EndElement2, BlankElement; // all blank to begin with, can only have max of 2 PrefDirs on a
14460  // given element as can't select 2-track elements
14461  if(!(Track->FindNonPlatformMatch(8, HLoc, VLoc, EndPosition, TrackElement))) // return if can't find one
14462  {
14463  Utilities->CallLogPop(214);
14464  return(false);
14465  }
14466  if(Track->IsLCAtHV(19, HLoc, VLoc))
14467  {
14468  TrainController->StopTTClockMessage(72, "Can't end a route on a level crossing");
14469  Utilities->CallLogPop(1908);
14470  return(false);
14471  }
14472 // cancel selection if on original start element
14473  if(EndPosition == StartRoutePosition)
14474  {
14475  Utilities->CallLogPop(215);
14476  return(false);
14477  }
14478  if(AutoSigsFlag)
14479  {
14480  if(TrackElement.TrackType == Buffers)
14481  {
14482  TrainController->StopTTClockMessage(19, "Can't create an automatic signal route into buffers");
14483  Utilities->CallLogPop(216);
14484  return(false);
14485  }
14486  }
14487  if((TrackElement.TrackType != SignalPost) && (TrackElement.TrackType != Buffers) && (TrackElement.TrackType != Continuation))
14488  {
14489  TrainController->StopTTClockMessage(20, "Must select a valid signal, buffers or continuation");
14490  Utilities->CallLogPop(217);
14491  return(false);
14492  }
14493 // check if train on element
14494  if(TrackElement.TrainIDOnElement > -1)
14495  {
14496  TrainController->StopTTClockMessage(22, "Can't end a route on a train");
14497  Utilities->CallLogPop(219);
14498  return(false);
14499  }
14500 // disallow if not in EveryPrefDir & set EndElement(s)
14501  bool InPrefDirFlag = false;
14502 
14503  bool FoundFlag;
14504  int PrefDirPos0 = -1;
14505  int PrefDirPos1 = -1;
14506  int PrefDirPos2 = -1;
14507  int PrefDirPos3 = -1;
14508 
14509  EveryPrefDir->GetVectorPositionsFromPrefDir4MultiMap(4, Track->TrackElementAt(86, EndPosition).HLoc, Track->TrackElementAt(87, EndPosition).VLoc, FoundFlag,
14510  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14511  int PrefDirVecPos[4] =
14512  {
14513  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
14514  };
14515 
14516  for(int x = 0; x < 4; x++)
14517  {
14518  int b = PrefDirVecPos[x];
14519  if(b > -1)
14520  {
14521  InPrefDirFlag = true;
14522  if(EndElement1.TrackVectorPosition == -1)
14523  {
14524  EndElement1 = EveryPrefDir->GetFixedPrefDirElementAt(33, b);
14525  }
14526  else
14527  {
14528  EndElement2 = EveryPrefDir->GetFixedPrefDirElementAt(34, b);
14529  }
14530  }
14531  }
14532  if(!InPrefDirFlag)
14533  {
14535  "Route and preferred direction mismatch. If no preferred direction then only red routes can be used. Green and blue route directions must correspond to the preferred direction.");
14536  Utilities->CallLogPop(220);
14537  return(false);
14538  }
14539 // check if in an existing route - can't be a bridge so can use a simple 'find'
14540 // bool InRoute = false;
14542  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(15, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
14543 
14544  if(RoutePair.first > -1)
14545  {
14546  if(RoutePair.second != 0) // not first element in existing route so no good
14547  {
14548  TrainController->StopTTClockMessage(24, "Can't end a route within or at the end of an existing route");
14549  Utilities->CallLogPop(221);
14550  return(false);
14551  }
14552  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(8, RoutePair.first).GetFixedPrefDirElementAt(35, RoutePair.second);
14553 // if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(, RouteElement.Conn[RouteElement.ELinkPos], RouteElement.ELinkPos)))
14554  if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(10, RouteElement.Conn[RouteElement.ELinkPos],
14555  RouteElement.ConnLinkPos[RouteElement.ELinkPos]))) // amended at v1.3.0 - had omitted ConnLinkPos - see above
14556  // discovered when timetable building for Joshua Coupe's railway. Also affects non-preferred routes - see below
14557  // first element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
14558  {
14559  TrainController->StopTTClockMessage(25, "Can't start a route within or at the end of an existing route");
14560  Utilities->CallLogPop(222);
14561  return(false);
14562  }
14563  EndElement1 = RouteElement;
14564  EndElement2 = BlankElement; // only need the route element
14565  EndPosition = EndElement1.TrackVectorPosition;
14566  ReqPosRouteID = IDInt(AllRoutes->GetFixedRouteAt(160, RoutePair.first).RouteID);
14567  }
14568 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
14569 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
14570 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
14571 
14572  if(EndElement1.HLoc >= StartElement1.HLoc)
14573  {
14575  SearchLimitHighH = EndElement1.HLoc + 15;
14576  }
14577  else
14578  {
14579  SearchLimitLowH = EndElement1.HLoc - 15;
14581  }
14582  if(EndElement1.VLoc >= StartElement1.VLoc)
14583  {
14585  SearchLimitHighV = EndElement1.VLoc + 15;
14586  }
14587  else
14588  {
14589  SearchLimitLowV = EndElement1.VLoc - 15;
14591  }
14592 /* dropped this for v0.4d - prevents ability to set routes for gaps that are widely separated, ok without it as search limited by SearchVector size
14593  check & TotalSearchCounts check
14594  if((abs(EndElement1.HLoc - StartElement1.HLoc) > 120) || (abs(EndElement1.VLoc - StartElement1.VLoc) > 120))
14595  {
14596  TrainController->StopTTClockMessage(65, "Unable to reach the selected element - too far ahead");
14597  Utilities->CallLogPop(1693);
14598  return false;
14599  }
14600 */
14601 // check if adjacent to start and disallow
14602  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
14603  {
14605  int AdjLinkPos = AllRoutes->GetFixedRouteAt(218, a).GetFixedPrefDirElementAt(244, 0).ELinkPos; // added at v1.3.1
14606 // if((EndElement1.Config[EndElement1.XLinkPos] != End) &&
14607 // (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition))
14608  if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
14609  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
14610  (EndElement1.ConnLinkPos[EndElement1.XLinkPos] == AdjLinkPos))
14611  {
14612  TrainController->StopTTClockMessage(26, "Can't end a route adjacent to the start of an existing route");
14613  Utilities->CallLogPop(223);
14614  return(false);
14615  }
14616 // else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End) &&
14617 // (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition))
14618  else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End)
14619  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
14620  (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (EndElement2.ConnLinkPos[EndElement2.XLinkPos] == AdjLinkPos))
14621  {
14622  TrainController->StopTTClockMessage(27, "Can't end a route adjacent to the start of an existing route");
14623  Utilities->CallLogPop(224);
14624  return(false);
14625  }
14626 // check if adjacent to end of a route & disallow
14628  if((EndOfRouteElement.Config[EndOfRouteElement.XLinkPos] != End) && (EndOfRouteElement.Conn[EndOfRouteElement.XLinkPos] == EndPosition))
14629  {
14630  TrainController->StopTTClockMessage(28, "Can't end a route adjacent to the end of an existing route");
14631  Utilities->CallLogPop(225);
14632  return(false);
14633  }
14634  }
14635 
14636 // check for same route as start element
14638  {
14639  TrainController->StopTTClockMessage(29, "Can't select same route as started in");
14640  Utilities->CallLogPop(226);
14641  return(false);
14642  }
14643 // check for a looping route
14644  if((ReqPosRouteID > -1) && (StartSelectionRouteID > -1))
14645  {
14647  {
14648  TrainController->StopTTClockMessage(69, "Can't create a route that loops back on itself");
14649  Utilities->CallLogPop(1844);
14650  return(false);
14651  }
14652  }
14653 // if there's a StartSelectionRouteID StartElement1 will be set to the last entry in the selected route
14654 // so search from this element. No need to add StartElement to the SearchVector since it already exists in a route
14655 // and don't want to add it again
14656  if(StartSelectionRouteID > -1)
14657  {
14658  if(SearchForPreferredRoute(0, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14659  AutoSigsFlag))
14660  {
14661  SetRouteSearchVectorGraphics(0, AutoSigsFlag, true); // change graphic colour to the route colour
14662  if(PointsToBeChanged(5))
14663  {
14664  PointsChanged = true;
14665  }
14666  Utilities->CallLogPop(227);
14667  return(true);
14668  }
14669  else if(!Track->SuppressRouteFailMessage)
14670  {
14671  //corrected at v2.7.0 - brackets were missed earlier so if SearchForPreferredRoute failed & else condition failed too then returned false with no message
14673  Utilities->CallLogPop(228);
14674  return(false);
14675  }
14676  }
14677  else
14678  {
14679 // Note: StartElement not in an existing route so was added to the searchvector during the earlier function
14680 // First check if selection adjacent to start element and if so use that [can't be as can't have 2 consecutive signals, but leave in]
14681 
14682 // added the XLinkPos checks because of Matt Blades error reported on 28/06/11, where StartElement2 matched EndPosition spuriously
14683 // note that a blank element will have XLinkPos set to -1
14684  if((StartElement1.XLinkPos > -1) && (StartElement1.Conn[StartElement1.XLinkPos] == EndPosition))
14685  {
14686  if(SearchForPreferredRoute(1, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14687  AutoSigsFlag))
14688  {
14689  SetRouteSearchVectorGraphics(1, AutoSigsFlag, true); // change graphic colour to the route colour
14690  if(PointsToBeChanged(6))
14691  {
14692  PointsChanged = true;
14693  }
14694  Utilities->CallLogPop(229);
14695  return(true);
14696  }
14697  else
14698  {
14700  {
14702  }
14703  Utilities->CallLogPop(230);
14704  return(false);
14705  }
14706  }
14707  else if((StartElement2.XLinkPos > -1) && (StartElement2.Conn[StartElement2.XLinkPos] == EndPosition))
14708  {
14709  if(SearchForPreferredRoute(2, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14710  AutoSigsFlag))
14711  {
14712  SetRouteSearchVectorGraphics(2, AutoSigsFlag, true); // change graphic colour to the route colour
14713  if(PointsToBeChanged(7))
14714  {
14715  PointsChanged = true;
14716  }
14717  Utilities->CallLogPop(231);
14718  return(true);
14719  }
14720  else
14721  {
14723  {
14725  }
14726  Utilities->CallLogPop(232);
14727  return(false);
14728  }
14729  }
14730  // now start off in the best direction
14731  int BestPos = Track->FindClosestLinkPosition(0, StartRoutePosition, EndPosition); // can only be 0 or 1
14732  // the following logic is very unstructured as extra bits have been added at different times and I'm reluctant to remove earlier bits in case
14733  // they cover situations that might be overlooked. A full analysis would enable it to be tidied up but it works (so far!) so I'll leave it as it is
14734  // unless new problems are found.
14735  if(StartElement1.XLinkPos == BestPos)
14736  {
14737  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
14738  if(SearchForPreferredRoute(3, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14739  AutoSigsFlag))
14740  {
14741  SetRouteSearchVectorGraphics(3, AutoSigsFlag, true); // change graphic colour to the route colour
14742  if(PointsToBeChanged(8))
14743  {
14744  PointsChanged = true;
14745  }
14746  Utilities->CallLogPop(233);
14747  return(true);
14748  }
14749  else if(StartElement2.TrackVectorPosition > -1)
14750  {
14751  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
14752  if(SearchForPreferredRoute(4, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14753  AutoSigsFlag))
14754  {
14755  SetRouteSearchVectorGraphics(4, AutoSigsFlag, true); // change graphic colour to the route colour
14756  if(PointsToBeChanged(9))
14757  {
14758  PointsChanged = true;
14759  }
14760  Utilities->CallLogPop(234);
14761  return(true);
14762  }
14763  }
14764  }
14765  else if(StartElement2.TrackVectorPosition > -1)
14766  {
14767  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
14768  if(SearchForPreferredRoute(5, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14769  AutoSigsFlag))
14770  {
14771  SetRouteSearchVectorGraphics(6, AutoSigsFlag, true); // change graphic colour to the route colour
14772  if(PointsToBeChanged(10))
14773  {
14774  ;
14775  }
14776  {
14777  PointsChanged = true;
14778  }
14779  Utilities->CallLogPop(1857);
14780  return(true);
14781  }
14782  else if(SearchForPreferredRoute(8, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14783  AutoSigsFlag))
14784  {
14785  SetRouteSearchVectorGraphics(7, AutoSigsFlag, true); // change graphic colour to the route colour
14786  if(PointsToBeChanged(11))
14787  {
14788  ;
14789  }
14790  {
14791  PointsChanged = true;
14792  }
14793  Utilities->CallLogPop(1858);
14794  return(true);
14795  }
14796  }
14797  else if(StartElement1.XLinkPos == (1 - BestPos))
14798  // added at v0.4d to use StartElement1 again with non-Best direction (may be only one & may not point in right direction)
14799  {
14800  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
14801  if(SearchForPreferredRoute(9, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14802  AutoSigsFlag))
14803  {
14804  SetRouteSearchVectorGraphics(8, AutoSigsFlag, true); // change graphic colour to the route colour
14805  if(PointsToBeChanged(12))
14806  {
14807  PointsChanged = true;
14808  }
14809  Utilities->CallLogPop(1864);
14810  return(true);
14811  }
14812  }
14813  }
14815  {
14817  }
14818  Utilities->CallLogPop(235);
14819  return(false);
14820 }
14821 
14822 // ---------------------------------------------------------------------------
14823 
14824 void TOneRoute::RouteImageMarker(int Caller, Graphics::TBitmap *Bitmap) const
14825 {
14826  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RouteImageMarker");
14827  if(PrefDirSize() == 0)
14828  {
14829  Utilities->CallLogPop(1704);
14830  return;
14831  }
14832  for(unsigned int x = 0; x < PrefDirSize(); x++)
14833  {
14834  TPrefDirElement TempPrefDirElement = PrefDirVector.at(x);
14835  if(TempPrefDirElement.EXGraphicPtr != 0) // Note: will be 0 if first element or last as leading point
14836  {
14837  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
14838  TempPrefDirElement.EXGraphicPtr);
14839  if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && PrefDirSize() > 1) // Route, no direction if a single element
14840  {
14841  if(x == 0)
14842  {
14843  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
14844  TempPrefDirElement.EntryDirectionGraphicPtr);
14845  }
14846  if(x == (PrefDirSize() - 1))
14847  {
14848  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
14849  TempPrefDirElement.EntryDirectionGraphicPtr);
14850  }
14851  }
14852  }
14853  }
14854 
14855  Utilities->CallLogPop(1705);
14856 }
14857 
14858 // ---------------------------------------------------------------------------
14859 
14860 bool TOneRoute::SearchForPreferredRoute(int Caller, TPrefDirElement PrefDirElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID,
14861  TOnePrefDir *EveryPrefDir, bool ConsecSignals, int EndPosition, bool AutoSigsFlag)
14862 
14863 /*
14864  Brief: similar to SearchForPrefDir but with a PrefDirElement instead of a TrackElement & with additional parameters.
14865  PrefDirElement is the starting element from which to search, it is NOT stored in searchvector during this function. If it's an
14866  element that's not already in a route it will have been stored in SearchVector during GetPreferredRouteStartElement.
14867  ReqPosRouteID is used when RequiredPosition is start of an existing route, else it's -1.
14868  Return false if any element (apart from RequiredPosition) is on an existing route.
14869  Return false if not on a PrefDir with same ELink (can't check XLink as may not be set - if it's a leading point in a recursive call - see later).
14870 
14871  Detail: Function is a continuous loop as examine each element on a potential route, exiting only if find
14872  the required position (return true & leave Searchvector as set up) or if fail (erase all SearchVector entries
14873  added during the function so as to leave it exactly as it was on entering, then return false).
14874  It is a recursive function (similar to SearchForPrefDir) to enable all possible point branches to be searched.
14875  A VectorCount is maintained to count elements added to the SearchVector, so that this number can be erased on failure
14876  of any branch. Enter with starting PrefDirElement & XLinkPos for that element, RequiredPosition - the
14877  TrackVectorPosition of the element to be searched for, ReqPosRouteID -
14878  the route number that the searched-for element is the start of if any, and set to -1 if no
14879  such route. A pointer to EveryPrefDir is also passed in since this is not accessible directly from
14880  this unit, together with the ConsecSignalsRoute and AutoSigsFlag flags.
14881  Create 2 TPrefDirElements - PrefDirElement1 and 2, for use later - ELink has to match the preceding XLink, so the only
14882  2 possible PrefDirs are for a leading point & its two trailing PrefDirs.
14883 
14884  Enter loop - note that PrefDirElement changes each time round the loop - check if PrefDirElement XLinkPos faces buffers
14885  or a continuation, and fail if so. Check if reached a valid next signal in ConsecSignalsRoute on any but firstpass
14886  (nonrecursive firstpass starts at a valid signal, and recursive firstpass always starts at points so doesn't matter
14887  for recursive calls), and fail if so as user should always select the next signal in a route if ConsecSignals set.
14888  Create a new TPrefDirElement - SearchElement, from PrefDirElement.Conn[XLinkPos], & set all FixedTrackPiece &
14889  TrackElement values, ELink & ELinkPos, and also XLink & XLinkPos unless element is a leading point.
14890  Check if element is already in searchvector (OK if a bridge & earlier entry on different track, but not OK if
14891  any other type of element), already in an existing route (OK if bridge & diff tracks, or start of an expected route),
14892  or if train on element (unless a bridge & train on different track).
14893  Check & fail for a fouled diagonal (unless element is a leading point - these checked later).
14894  Check element in EveryPrefDir with same ELink value & set PrefDirElement1, & also 2 if element is
14895  a leading point where both trailing directions are in EveryPrefDir, if not fail.
14896  Check if found RequiredPosition & that it's a signal/buffer/continuation. If OK save in SearchVector with
14897  AutoSignals member set if AutoSigsFlag set, then return true.
14898  Check & fail if a buffer or continuation (unless it is the RequiredPosition, in which case will have succeeded in the above check).
14899 
14900  Now check if a leading point and if so set XLinkPos to the 'set' exit & check if that XLink is in EveryPrefDir,
14901  by comparing with PrefDirElement1 or 2, fail if not. If valid check for a fouled diagonal and fail if so. If OK
14902  store element in SearchVector with AutoSignals member set if AutoSigsFlag set & do a recursive search using
14903  this element and XLinkPos, other parameters are passed in without change. If succeed return true, else erase the last element in
14904  SearchVector (i.e the earlier stored leading point element prior to doing the recursive search) & set XLinkPos to the 'unset' exit to
14905  check the other trailing direction. Then proceed in same way as above, i.e. fouled diagonal & recursive search etc. If
14906  fail on this XLinkPos then have tried & failed on both ways out from the leading point so erase the searchvector & return false.
14907 
14908  If not a leading point store the element (can only be PrefDirElement1 as not a leading point), then set
14909  up the next loop values of PrefDirElement & XLinkPos from SearchElement & NextXLinkPos and repeat the while loop.
14910 */
14911 
14912 {
14913  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForPreferredRoute," + PrefDirElement.LogPrefDir() + "," +
14914  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition) + "," + AnsiString(ReqPosRouteID.GetInt()) + "," + AnsiString(EndPosition) + "," +
14915  AnsiString((short)AutoSigsFlag));
14916  int VectorCount = 0;
14917  TPrefDirElement PrefDirElement1, PrefDirElement2, BlankElement;
14918 
14919 // check for a fouled diagonal for first element. Added for v1.3.2
14920  if((PrefDirElement.XLink == 1) || (PrefDirElement.XLink == 3) || (PrefDirElement.XLink == 7) || (PrefDirElement.XLink == 9))
14921  {
14922  if(AllRoutes->DiagonalFouledByRouteOrTrain(0, PrefDirElement.HLoc, PrefDirElement.VLoc, PrefDirElement.XLink))
14923  {
14924  for(int x = 0; x < VectorCount; x++)
14925  {
14926  SearchVector.erase(SearchVector.end() - 1);
14927  }
14928  Utilities->CallLogPop(2043);
14929  return(false);
14930  }
14931  }
14932  bool FirstPass = true;
14933 
14934  while(true)
14935  {
14936  if(AutoSigsFlag && Track->IsLCAtHV(24, PrefDirElement.HLoc, PrefDirElement.VLoc))
14937  {
14938  Track->LCFoundInAutoSigsRoute = true;
14939  }
14940  if(Track->IsLCBarrierFlashingAtHV(1, PrefDirElement.HLoc, PrefDirElement.VLoc)) // can't set a route through a flashing barrier
14941  {
14942  for(int x = 0; x < VectorCount; x++)
14943  {
14944  SearchVector.erase(SearchVector.end() - 1);
14945  }
14946  Utilities->CallLogPop(1926);
14947  return(false);
14948  }
14949  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == End) // buffers or continuation
14950  {
14951  for(int x = 0; x < VectorCount; x++)
14952  {
14953  SearchVector.erase(SearchVector.end() - 1);
14954  }
14955  Utilities->CallLogPop(236);
14956  return(false);
14957  }
14958  if(!FirstPass && ConsecSignals && (PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal))
14959  // reached a valid signal that isn't the required position, user should always select the next
14960  // signal in a route so have to fail
14961  // won't affect recurive searches as for them the first pass element is always a point
14962  {
14963  for(int x = 0; x < VectorCount; x++)
14964  {
14965  SearchVector.erase(SearchVector.end() - 1);
14966  }
14967  Utilities->CallLogPop(237);
14968  return(false);
14969  }
14970  FirstPass = false;
14971  int NextPosition = PrefDirElement.Conn[XLinkPos];
14972  TTrackElement NextTrackElement = Track->TrackElementAt(88, NextPosition);
14973  TPrefDirElement SearchElement(NextTrackElement);
14974  SearchElement.TrackVectorPosition = NextPosition;
14975  int NextELinkPos = PrefDirElement.ConnLinkPos[XLinkPos];
14976  SearchElement.ELinkPos = NextELinkPos;
14977  SearchElement.ELink = SearchElement.Link[NextELinkPos]; // Note ELink isn't necessarily 10 - last XLink, as last element may have
14978  // been a gap. Now have all FixedTrackPiece & TrackElement values, + TrackVectorPosition, ELink & ELinkPos
14979  int NextXLinkPos;
14980  if(SearchElement.ELinkPos == 0)
14981  {
14982  NextXLinkPos = 1;
14983  }
14984  if(SearchElement.ELinkPos == 1)
14985  {
14986  NextXLinkPos = 0;
14987  }
14988  if(SearchElement.ELinkPos == 2)
14989  {
14990  NextXLinkPos = 3;
14991  }
14992  if(SearchElement.ELinkPos == 3)
14993  {
14994  NextXLinkPos = 2;
14995  }
14996  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
14997  {
14998  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
14999 // note that may be buffers, continuation or gap
15000  SearchElement.XLinkPos = NextXLinkPos;
15001  }
15002 // can't set XLink or XLinkPos yet if the element is a leading point.
15003 
15004 // check if reached an earlier position on search PrefDir (was OK in SearchForPrefDir if entry values different, but not OK for a route)
15005  for(unsigned int x = 0; x < SearchVector.size(); x++)
15006  {
15007  if(SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition)
15008  {
15009  if((SearchElement.TrackType != Bridge) || ((SearchElement.TrackType == Bridge) && (SearchElement.ELink == SearchVector.at(x).ELink)))
15010  // OK if a bridge & routes on different tracks
15011  {
15012  for(int x = 0; x < VectorCount; x++)
15013  {
15014  SearchVector.erase(SearchVector.end() - 1);
15015  }
15016  Utilities->CallLogPop(238);
15017  return(false);
15018  }
15019  }
15020  }
15021 
15022 // check if element in an existing route (OK if bridge & diff tracks, or start of an expected route)
15023  TAllRoutes::TRouteElementPair SecondPair;
15025  Track->TrackElementAt(89, SearchElement.TrackVectorPosition).HLoc, Track->TrackElementAt(90, SearchElement.TrackVectorPosition).VLoc, SecondPair);
15026  if(RoutePair.first > -1)
15027  {
15028  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
15029  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(12, RoutePair.first).GetFixedPrefDirElementAt(38,
15030  RoutePair.second).ELinkPos)))
15031  {
15032  // still OK if start of an expected route
15033  if((ReqPosRouteID == IDInt(-1)) || ((int)RoutePair.first != AllRoutes->GetRouteVectorNumber(2, ReqPosRouteID)) || (RoutePair.second != 0))
15034  {
15035  for(int x = 0; x < VectorCount; x++)
15036  {
15037  SearchVector.erase(SearchVector.end() - 1);
15038  }
15039  Utilities->CallLogPop(239);
15040  return(false); // only allow for start of an expected route
15041  }
15042  }
15043  }
15044  if(SecondPair.first > -1) // if reach here & secondpair present then must fail as can't escape both existing routes, but leave check as before anyway
15045  {
15046  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
15047  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(13, SecondPair.first).GetFixedPrefDirElementAt(39,
15048  SecondPair.second).ELinkPos)))
15049  {
15050  // still OK if start of an expected route
15051  if((ReqPosRouteID == IDInt(-1)) || ((int)SecondPair.first != AllRoutes->GetRouteVectorNumber(3, ReqPosRouteID)) || (SecondPair.second != 0))
15052  {
15053  for(int x = 0; x < VectorCount; x++)
15054  {
15055  SearchVector.erase(SearchVector.end() - 1);
15056  }
15057  Utilities->CallLogPop(240);
15058  return(false); // only allow for start of an expected route
15059  }
15060  }
15061  }
15062 // check if a train on element, unless a bridge & train on different track
15063 // OK of same train as start element - no drop this
15064 // if(SearchElement.TrainIDOnElement != StartSelectionTrainID)
15065  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType != Bridge))
15066  {
15067  for(int x = 0; x < VectorCount; x++)
15068  {
15069  SearchVector.erase(SearchVector.end() - 1);
15070  }
15071  Utilities->CallLogPop(241);
15072  return(false);
15073  }
15074  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType == Bridge))
15075  {
15076  if((SearchElement.ELinkPos < 2) && (SearchElement.TrainIDOnBridgeTrackPos01 > -1))
15077  {
15078  for(int x = 0; x < VectorCount; x++)
15079  {
15080  SearchVector.erase(SearchVector.end() - 1);
15081  }
15082  Utilities->CallLogPop(242);
15083  return(false);
15084  }
15085  else if((SearchElement.ELinkPos > 1) && (SearchElement.TrainIDOnBridgeTrackPos23 > -1))
15086  {
15087  for(int x = 0; x < VectorCount; x++)
15088  {
15089  SearchVector.erase(SearchVector.end() - 1);
15090  }
15091  Utilities->CallLogPop(243);
15092  return(false);
15093  }
15094  }
15095 // check for a fouled diagonal (if not leading point - these checked later - leading point XLink == -1)
15096  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
15097  {
15098  if(AllRoutes->DiagonalFouledByRouteOrTrain(7, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
15099  {
15100  for(int x = 0; x < VectorCount; x++)
15101  {
15102  SearchVector.erase(SearchVector.end() - 1);
15103  }
15104  Utilities->CallLogPop(244);
15105  return(false);
15106  }
15107  }
15108 // check element in EveryPrefDir with same ELink (XLink may not be set) & save up to 2 elements (for leading point & 2 trailing PrefDirs)
15109 // note that point XLinks checked later, otherwise XLink fully defined by ELink so only need to check ELink
15110  bool InPrefDirFlag = false;
15111  PrefDirElement1 = BlankElement;
15112  PrefDirElement2 = BlankElement;
15113 
15114  bool FoundFlag;
15115  int PrefDirPos0 = -1;
15116  int PrefDirPos1 = -1;
15117  int PrefDirPos2 = -1;
15118  int PrefDirPos3 = -1;
15120  Track->TrackElementAt(92, SearchElement.TrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
15121  int PrefDirVecPos[4] =
15122  {
15123  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
15124  };
15125  for(int x = 0; x < 4; x++)
15126  {
15127  int b = PrefDirVecPos[x];
15128  if((b > -1) && (EveryPrefDir->GetFixedPrefDirElementAt(40, b).ELink == SearchElement.ELink))
15129  {
15130  InPrefDirFlag = true;
15131  if(PrefDirElement1.TrackVectorPosition == -1)
15132  {
15133  PrefDirElement1 = EveryPrefDir->GetFixedPrefDirElementAt(41, b);
15134  }
15135  else
15136  {
15137  PrefDirElement2 = EveryPrefDir->GetFixedPrefDirElementAt(42, b);
15138  }
15139  }
15140  }
15141  if(!InPrefDirFlag)
15142  {
15143  for(int x = 0; x < VectorCount; x++)
15144  {
15145  SearchVector.erase(SearchVector.end() - 1);
15146  }
15147  Utilities->CallLogPop(245);
15148  return(false);
15149  }
15150 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
15151 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
15152 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
15154  {
15155  for(int x = 0; x < VectorCount; x++)
15156  {
15157  SearchVector.erase(SearchVector.end() - 1);
15158  }
15159  Utilities->CallLogPop(1690);
15160  return(false);
15161  }
15162 // check if found it
15163  if(SearchElement.TrackVectorPosition == RequiredPosition)
15164  {
15165 // need to ensure a signal/buffer/continuation
15166  if((SearchElement.Config[SearchElement.XLinkPos] != Signal) && (SearchElement.Config[SearchElement.XLinkPos] != End) &&
15167  (SearchElement.Config[SearchElement.XLinkPos] != Continuation))
15168  {
15169  TrainController->StopTTClockMessage(94, "Must select a valid signal, buffers or continuation"); //added at v2.7.0
15171  for(int x = 0; x < VectorCount; x++)
15172  {
15173  SearchVector.erase(SearchVector.end() - 1);
15174  }
15175  Utilities->CallLogPop(246);
15176  return(false);
15177  } // if((SearchElement.Config[SearchElement.XLinkPos] != Signal).......
15178 
15179  if(AutoSigsFlag)
15180  {
15181  PrefDirElement1.AutoSignals = true;
15182  }
15183  PrefDirElement1.PrefDirRoute = true;
15185  {
15187  {
15188  TrainController->StopTTClockMessage(76, "Can't create an automatic signal route through a level crossing");
15190  }
15191  for(int x = 0; x < VectorCount; x++)
15192  {
15193  SearchVector.erase(SearchVector.end() - 1);
15194  }
15195  Utilities->CallLogPop(1928);
15196  return(false);
15197  }
15198  SearchVector.push_back(PrefDirElement1); // must be 1 as it's a simple element
15199  VectorCount++; // not really needed but include for tidyness
15200  TotalSearchCount++;
15201  Utilities->CallLogPop(247);
15202  return(true);
15203  } // if(SearchElement.TrackVectorPosition == RequiredPosition)
15204 
15205 // check if a buffer or continuation (end of search on this leg if not found by now)
15206  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
15207  {
15208  for(int x = 0; x < VectorCount; x++)
15209  {
15210  SearchVector.erase(SearchVector.end() - 1);
15211  }
15212  Utilities->CallLogPop(248);
15213  return(false);
15214  }
15215 // check if SearchVector exceeds a size of 150
15216  if(SearchVector.size() > 150)
15217  {
15218  for(int x = 0; x < VectorCount; x++)
15219  {
15220  SearchVector.erase(SearchVector.end() - 1);
15221  }
15222  Utilities->CallLogPop(1420);
15223  return(false);
15224  }
15225 // check if reached a leading point
15226  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead))
15227  {
15228 // XLink set to points 'set' position - Attribute == 0, SearchPos1 = 1 & SearchPos2 = 3; Attribute == 1, SearchPos1 = 3 & SearchPos2 = 1;
15229  int SearchPos1 = SearchElement.Attribute + 1;
15230  int SearchPos2;
15231  if(SearchPos1 == 2)
15232  {
15233  SearchPos1++;
15234  }
15235  if(SearchPos1 == 1)
15236  {
15237  SearchPos2 = 3;
15238  }
15239  else
15240  {
15241  SearchPos2 = 1;
15242  }
15243  SearchElement.XLink = SearchElement.Link[SearchPos1];
15244  SearchElement.XLinkPos = SearchPos1;
15245  InPrefDirFlag = false;
15246  if(SearchElement.XLink == PrefDirElement1.XLink)
15247  {
15248  SearchElement = PrefDirElement1; // set to an existing PrefDir element so that exnumber & graphics set
15249  InPrefDirFlag = true;
15250  }
15251  else if(SearchElement.XLink == PrefDirElement2.XLink)
15252  {
15253  SearchElement = PrefDirElement2;
15254  InPrefDirFlag = true;
15255  }
15256 // push element with XLink set to position [SearchPos1] if on a PrefDir
15257  if(InPrefDirFlag)
15258  {
15259 // check for a fouled diagonal for leading point for XLinkPos == 1)
15260  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
15261  {
15262  if(AllRoutes->DiagonalFouledByRouteOrTrain(1, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
15263  {
15264  for(int x = 0; x < VectorCount; x++)
15265  {
15266  SearchVector.erase(SearchVector.end() - 1);
15267  }
15268  Utilities->CallLogPop(249);
15269  return(false);
15270  }
15271  }
15272  if(AutoSigsFlag)
15273  {
15274  SearchElement.AutoSignals = true;
15275  }
15276  SearchElement.PrefDirRoute = true;
15277  SearchVector.push_back(SearchElement);
15278  VectorCount++;
15279  TotalSearchCount++;
15280 // recursive search at XLinkPos of SearchPos1 (i.e. 'set' trailing exit)
15281  if(SearchForPreferredRoute(6, SearchElement, SearchPos1, RequiredPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15282  AutoSigsFlag))
15283  {
15285  {
15287  {
15288  TrainController->StopTTClockMessage(77, "Can't create an automatic signal route through a level crossing");
15290  }
15291  for(int x = 0; x < VectorCount; x++)
15292  {
15293  SearchVector.erase(SearchVector.end() - 1);
15294  }
15295  Utilities->CallLogPop(1929);
15296  return(false);
15297  }
15298  Utilities->CallLogPop(250);
15299  return(true);
15300  }
15301  else
15302  {
15303 // remove leading point with XLinkPos [1]
15304  SearchVector.erase(SearchVector.end() - 1);
15305  VectorCount--;
15306  }
15307  }
15308 // XLink set to position [SearchPos2]
15309  SearchElement.XLink = SearchElement.Link[SearchPos2];
15310  SearchElement.XLinkPos = SearchPos2;
15311  if(SearchElement.XLink == PrefDirElement1.XLink)
15312  {
15313  SearchElement = PrefDirElement1; // set to an existing PrefDir element so that exnumber & graphics set
15314  }
15315  else if(SearchElement.XLink == PrefDirElement2.XLink)
15316  {
15317  SearchElement = PrefDirElement2;
15318  }
15319  else // failed to find a valid exit from the point
15320  {
15321  for(int x = 0; x < VectorCount; x++)
15322  {
15323  SearchVector.erase(SearchVector.end() - 1);
15324  }
15325  Utilities->CallLogPop(251);
15326  return(false);
15327  }
15328 // check for a fouled diagonal for leading point for XLinkPos == SearchPos2)
15329  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
15330  {
15331  if(AllRoutes->DiagonalFouledByRouteOrTrain(2, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
15332  {
15333  for(int x = 0; x < VectorCount; x++)
15334  {
15335  SearchVector.erase(SearchVector.end() - 1);
15336  }
15337  Utilities->CallLogPop(252);
15338  return(false);
15339  }
15340  }
15341 // push element with XLink set to position [SearchPos2]
15342  if(AutoSigsFlag)
15343  {
15344  SearchElement.AutoSignals = true;
15345  }
15346  SearchElement.PrefDirRoute = true;
15347  SearchVector.push_back(SearchElement);
15348  VectorCount++;
15349  TotalSearchCount++;
15350 // recursive search at XLinkPos of SearchPos2 (i.e. 'unset' trailing exit)
15351  if(SearchForPreferredRoute(7, SearchElement, SearchPos2, RequiredPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15352  AutoSigsFlag))
15353  {
15355  {
15357  {
15358  TrainController->StopTTClockMessage(78, "Can't create an automatic signal route through a level crossing");
15360  }
15361  for(int x = 0; x < VectorCount; x++)
15362  {
15363  SearchVector.erase(SearchVector.end() - 1);
15364  }
15365  Utilities->CallLogPop(1930);
15366  return(false);
15367  }
15368  Utilities->CallLogPop(1592);
15369  return(true);
15370  }
15371  else
15372  {
15373  for(int x = 0; x < VectorCount; x++)
15374  {
15375  SearchVector.erase(SearchVector.end() - 1);
15376  }
15377  Utilities->CallLogPop(253);
15378  return(false);
15379  }
15380  } // if leading point
15381 
15382 // here if ordinary element, push it, inc vector & update PrefDirElement ready for next element on PrefDir
15383  SearchElement = PrefDirElement1;
15384  if(AutoSigsFlag)
15385  {
15386  SearchElement.AutoSignals = true;
15387  }
15388  SearchElement.PrefDirRoute = true;
15389  SearchVector.push_back(SearchElement);
15390  VectorCount++;
15391  TotalSearchCount++;
15392  XLinkPos = SearchElement.XLinkPos; // wasn't a leading point so XLinkPos defined
15393  PrefDirElement = SearchElement;
15394  } // while(true)
15395 }
15396 
15397 // ---------------------------------------------------------------------------
15398 
15399 void TOneRoute::ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
15400 {
15401 /*
15402  For routes, as opposed to PrefDirs, the new route elements are first entered into SearchVector,
15403  and the new or extended route created from that. Hence action varies depending on whether
15404  it is a completely new route, or an extension of an existing route at the beginning or the end.
15405  Note that a single route cannot contain both AutoSig & non-AutoSig elements, each route of AutoSig elements
15406  has its own identity. A single route can however have a mixture of Unrestricted and PreferredRoute elements
15407 
15408  Ignore if SearchVector empty, and check that all the new elements in SearchVector are valid.
15409  Check if route end selection is in an existing route (ReqPosRouteID > -1), and if so proceed as follows:-
15410  if both new and existing routes non-autosig, add the old route to the SearchVector then delete the old route;
15411  if both new and existing routes autosig, add the old route to the SearchVector then delete the old route;
15412  in both the above cases if RequPosRouteNumber is less than StartSelectionRouteNumber then StartSelectionRouteNumber
15413  is decremented;
15414  if new route autosig and existing route non-autosig, keep the final search element in the new route & remove it (i.e first element)
15415  from the existing route, then enter the new route into the AllRoutesVector;
15416  if new route non-autosig and existing route autosig, drop the final search element in the new route, leave the existing route as it is,
15417  then enter the new route into the AllRoutesVector.
15418 
15419  Check if StartSelectionRouteID set (extending an existing route) and if so proceed as follows:-
15420  if both new and existing routes non-autosig, then add the new route to the existing route (start element not stored in searchvector);
15421  if both new and existing routes autosig, then add the new route to the existing route (start element not stored in searchvector);
15422  in both the above cases validate the extended route, then call SetRoutePoints & SetRouteSignals for the extended route and return.
15423  if new route autosig and existing route non-autosig, remove the last route element from the existing route, make it an AutoSig element,
15424  then add it to the start of the new route, then check its validity, enter it into the AllRoutesVector, call SetRoutePoints & SetRouteSignals
15425  for the new route and return;
15426  if new route non-autosig and existing route autosig, leave the existing route as it is, check its validity, then just enter the new
15427  route into the AllRoutesVector, finally call SetRoutePoints & SetRouteSignals for the new route and return.
15428 
15429  If not returned by now the route in SearchVector is to be added as a new route, so check its validity, create a new route using
15430  StoreOneRoute, call SetRoutePoints & SetRouteSignals and return. In practice the validity check, storage into AllRoutesVector and
15431  SetRoutePoints & SetRouteSignals call are combined for the above three cases.
15432 
15433 */
15434  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertAndAddPreferredRouteSearchVector," +
15435  AnsiString(ReqPosRouteID.GetInt()) + "," + AnsiString((short)AutoSigsFlag));
15436  if(SearchVector.size() < 1)
15437  {
15438  Utilities->CallLogPop(254);
15439  return;
15440  }
15442  if(!ValidatePrefDir(3)) // check the new route elements in SearchVector
15443  {
15444  Utilities->CallLogPop(255);
15445  return;
15446  }
15447  TAllRoutes::TLockedRouteClass LockedRouteObject;
15448 
15450  unsigned int TruncatePrefDirPosition = 0;
15451 
15452  if(ReqPosRouteID > -1) // Note that ReqPosRouteID != StartRouteNumber as would have failed in GetNextRouteElement
15453 /* if have ReqPosRouteID:
15454  if both new and existing routes non-autosig, then add the old route to the SearchVector then delete the old route
15455  if both new and existing routes autosig, then add the old route to the SearchVector then delete the old route
15456  if new route autosig and existing route non-autosig, keep the final search element in the new route & remove it (i.e first element) from
15457  the existing route, then enter the new route into the AllRoutesVector
15458  if new route non-autosig and existing route autosig, drop the final search element in the new route, leave the existing route as it is,
15459  then enter the new route into the AllRoutesVector
15460 */
15461  {
15464  {
15465  for(unsigned int x = 1; x < AllRoutes->GetFixedRouteAtIDNumber(21, ReqPosRouteID).PrefDirSize();
15466  x++) // start at 1 as first element already in SearchVector
15467  {
15469  }
15470  // note that route numbers in map adjusted when ReqPos route cleared
15472  // create a new locked route object (apart from RouteNumber) if required, for use later (LockedRouteFoundDuringRouteBuilding
15473  // set during ClearRouteDuringRouteBuildingAt
15475  {
15478  LockedRouteObject.LastXLinkPos = AllRoutes->LockedRouteLastXLinkPos;
15479  LockedRouteObject.LockStartTime = AllRoutes->LockedRouteLockStartTime;
15480  }
15481  }
15483  {
15485  AllRoutes->RemoveRouteElement(3, RouteElement.HLoc, RouteElement.VLoc, RouteElement.ELink);
15486  }
15488  {
15489  SearchVector.pop_back();
15490  }
15491  }
15492  if(StartSelectionRouteID > -1)
15493 /* if have StartSelectionRouteID:
15494  if both new and existing routes non-autosig, then add the new route to the existing route (start element not stored in searchvector)
15495  if both new and existing routes autosig, then add the new route to the existing route (start element not stored in searchvector)
15496  if new route autosig and existing route non-autosig, remove the last route element from the existing route, make it an AutoSig element,
15497  then add it to the start of the new route, then enter the new route into the AllRoutesVector
15498  if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
15499 */
15500  {
15502  // need to test because may have been removed by a train moving in the wrong direction between first and last route selections - added at v1.3.1
15503  {
15506  {
15507  int RouteNumber = AllRoutes->GetRouteVectorNumber(0, StartSelectionRouteID);
15508  for(unsigned int x = 0; x < SearchVector.size(); x++)
15509  {
15511  RouteNumber, GetFixedSearchElementAt(3, x));
15512  // find & store locked route truncate position in PrefDirVector for later use
15514  {
15515  if(GetFixedSearchElementAt(15, x).TrackVectorPosition == int(AllRoutes->LockedRouteTruncateTrackVectorPosition))
15516  {
15517  TruncatePrefDirPosition = AllRoutes->GetFixedRouteAt(172, RouteNumber).PrefDirSize() - 1;
15518  }
15519  }
15520  }
15522  {
15523  throw Exception("Error - failed to validate extended route for preferred route");
15524  }
15527  if(!AutoSigsFlag)
15528  {
15529  AllRoutes->GetModifiableRouteAtIDNumber(7, StartSelectionRouteID).SetLCChangeValues(0, true); // ConsecSignalsRoute is true
15530  }
15531  // now add the reinstated locked route if required and set signals accordingly
15533  {
15534  LockedRouteObject.RouteNumber = RouteNumber;
15535  AllRoutes->LockedRouteVector.push_back(LockedRouteObject);
15536  // now reset the signals for the locked route
15537  AllRoutes->SetAllRearwardsSignals(9, 0, RouteNumber, TruncatePrefDirPosition);
15538  for(int c = AllRoutes->GetFixedRouteAt(173, RouteNumber).PrefDirSize() - 1; c >= (int)TruncatePrefDirPosition;
15539  c--) // must use int for >= test to succeed when TruncatePrefDirPosition == 0
15540  {
15541  // return all signals to red in route section to be truncated
15542  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(174, RouteNumber).PrefDirVector.at(c);
15543  TTrackElement & TrackElement = Track->TrackElementAt(812, PrefDirElement.TrackVectorPosition);
15544  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
15545  {
15546  TrackElement.Attribute = 0;
15547  Track->PlotSignal(10, TrackElement, Display);
15548  Display->PlotOutput(113, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
15549  Display->PlotOutput(114, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
15550  }
15551  }
15552  }
15553  AllRoutes->CheckMapAndRoutes(1); // test
15554  Utilities->CallLogPop(256);
15555  return;
15556  }
15558  {
15561  RouteElement.AutoSignals = true;
15562  RouteElement.EXGraphicPtr = RouteElement.GetRouteGraphicPtr(AutoSigsFlag, true);
15563  RouteElement.EntryDirectionGraphicPtr = RouteElement.GetDirectionRouteGraphicPtr(AutoSigsFlag, true); // as above
15564  AllRoutes->RemoveRouteElement(4, RouteElement.HLoc, RouteElement.VLoc, RouteElement.ELink);
15565  SearchVector.insert(SearchVector.begin(), 1, RouteElement);
15566  }
15567  }
15568  else
15569  {
15571  }
15572 // if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the
15573 // AllRoutesVector hence nothing to do here
15574  }
15575  PrefDirVector = SearchVector; // need to copy again since SearchVector may have been extended
15576  if(!ValidatePrefDir(5)) // validate PrefDir for all new route elements
15577  {
15578  throw Exception("Error - failed to validate single route for preferred route");
15579  }
15580  AllRoutes->StoreOneRoute(1, this);
15581  AllRoutes->GetModifiableRouteAt(3, AllRoutes->AllRoutesSize() - 1).SetRoutePoints(1); // new addition
15582  AllRoutes->GetModifiableRouteAt(16, AllRoutes->AllRoutesSize() - 1).SetRouteSignals(5); // new addition
15583  if(!AutoSigsFlag)
15584  {
15585  AllRoutes->GetModifiableRouteAt(18, AllRoutes->AllRoutesSize() - 1).SetLCChangeValues(1, true); // ConsecSignalsRoute is true
15586  }
15587  AllRoutes->CheckMapAndRoutes(2); // test
15588  Utilities->CallLogPop(257);
15589 }
15590 
15591 // ---------------------------------------------------------------------------
15592 
15593 bool TOneRoute::GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool Callon) // Return true if OK.
15594 {
15595 /*
15596  If Callon true then this routine is called from MainScreenMouseDown2 in InterfaceUnit.cpp to set an unrestricted call-on route - messages are suppressed
15597  Clear the PrefDir and search vectors using ClearRoute(). Check selection matches a TrackElement
15598  & ensure signal/buffers/continuation.
15599  Note that can't select ConsecSignalsRoute for non-preferred routes.
15600  Check if train on element & disallow.
15601  Set default values for retained parameters:-
15602  StartRoutePosition = TrackVectorPosition of the element to be used as the start of the route;
15603  StartSelectionRouteID = route that selection starts in if there is one;
15604 
15605  Create 2 PrefDirElements from the TrackElement, setting all values corresponding to the 2 possible PrefDirs
15606  through the element (can only be 2 as 3 & 4 ended elements aren't allowed) & make an EXNumber check for
15607  validity. This is just for safety reasons, the PrefDir values aren't used.
15608  StartElement1 & 2 are set to these PrefDirelements.
15609 
15610  There is no need to check that the element lies in a PrefDir for nonpreferred selections.
15611 
15612  Check if in an existing route & if so only allow last element to be selected - ensure it has somewhere to go!
15613  Set StartElement1, StartSelectionRouteID and StartRoutePosition to correspond to the route end element and
15614  blank StartElement2 (only want to use the route element), then return true.
15615  Check if adjacent to start or end of an existing route & disallow if so.
15616  If not in a route and not failed so far then reset all Link, all LinkPos, & EXNumber values to -1, and CheckCount
15617  to 4 for StartElement1, & blank StartElement2. The remaining data members will be set later in
15618  SetRemainingSearchVectorValues().
15619  Finally add the required element to the SearchVector & return true.
15620 
15621 */
15622  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNonPreferredRouteStartElement," + AnsiString(HLoc) + "," +
15623  AnsiString(VLoc) + "," + AnsiString((short)Callon));
15624  ClearRoute();
15625  int TrackVectorPosition;
15626  TTrackElement TrackElement;
15627  TPrefDirElement FirstElement, LastElement;
15628 
15629  if(!(Track->FindNonPlatformMatch(9, HLoc, VLoc, TrackVectorPosition, TrackElement)))
15630  {
15631  Utilities->CallLogPop(258);
15632  return(false);
15633  }
15634  if((TrackElement.TrackType == Points) || (TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
15635  {
15636  if(!Callon)
15637  {
15638  TrainController->StopTTClockMessage(34, "Can't select points, bridge or crossover when route building");
15639  }
15640 // makes later adjacent route checks too complicated
15641  Utilities->CallLogPop(259);
15642  return(false);
15643  }
15644  if(Track->IsLCAtHV(21, HLoc, VLoc))
15645  {
15646  TrainController->StopTTClockMessage(74, "Can't start a route on a level crossing");
15647  Utilities->CallLogPop(1910);
15648  return(false);
15649  }
15650 // check if selected a train & disallow if so
15651  if(TrackElement.TrainIDOnElement > -1)
15652  {
15653  if(!Callon)
15654  {
15655  TrainController->StopTTClockMessage(35, "Can't start a route on a train");
15656  }
15657  Utilities->CallLogPop(260);
15658  return(false);
15659  }
15660 // check if selected a locked route element & disallow (can only be a 2-track element so only need check XLinkPos values of 0 & 1
15661  TPrefDirElement PrefDirElement;
15662  int LockedVectorNumber;
15663 
15664  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(3, TrackVectorPosition, 0, PrefDirElement, LockedVectorNumber))
15665  {
15666  if(!Callon)
15667  {
15668  TrainController->StopTTClockMessage(36, "Can't start a route on a locked route");
15669  }
15670  Utilities->CallLogPop(261);
15671  return(false);
15672  }
15673  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(4, TrackVectorPosition, 1, PrefDirElement, LockedVectorNumber))
15674  {
15675  if(!Callon)
15676  {
15677  TrainController->StopTTClockMessage(37, "Can't start a route on a locked route");
15678  }
15679  Utilities->CallLogPop(262);
15680  return(false);
15681  }
15683 // AdjacentStartRouteNumber = -1;
15684  StartRoutePosition = TrackVectorPosition;
15685 // StartRouteSelectPosition = TrackVectorPosition;
15686 
15687  TPrefDirElement PrefDirElement1(TrackElement); // 1 & 2 for the 2 possible PrefDirs at this location
15688  TPrefDirElement PrefDirElement2(TrackElement);
15689 
15690  PrefDirElement1.TrackVectorPosition = TrackVectorPosition;
15691  PrefDirElement2.TrackVectorPosition = TrackVectorPosition;
15692  TPrefDirElement BlankElement;
15693 
15694  PrefDirElement1.ELinkPos = 0;
15695  PrefDirElement1.XLinkPos = 1;
15696  PrefDirElement1.ELink = PrefDirElement1.Link[0];
15697  PrefDirElement1.XLink = PrefDirElement1.Link[1];
15698  if(!(PrefDirElement1.EntryExitNumber()))
15699  {
15700  throw Exception("Error, No EXNumber for PrefDirElement1 in GetNonPreferredRouteStartElement");
15701  // no need for bridge check as bridge selections not allowed
15702  }
15703  PrefDirElement1.CheckCount = 9;
15704  PrefDirElement2.ELinkPos = 1;
15705  PrefDirElement2.XLinkPos = 0;
15706  PrefDirElement2.ELink = PrefDirElement2.Link[1];
15707  PrefDirElement2.XLink = PrefDirElement2.Link[0];
15708  if(!(PrefDirElement2.EntryExitNumber()))
15709  {
15710  throw Exception("Error, No EXNumber for PrefDirElement2 in GetNonPreferredRouteStartElement");
15711  }
15712  PrefDirElement2.CheckCount = 9; // both now set
15713 
15714 // set StartElements to the above PrefDirElements
15715  StartElement1 = PrefDirElement1;
15716  StartElement2 = PrefDirElement2;
15717 
15718 // no PrefDir check needed as doesn't need to be in a PrefDir
15719 
15720 // look for exact match in a route first - can't be a 3 or 4 track element so only need to look for one TRouteElementPair
15722  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(1, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
15723 
15724  if(RoutePair.first > -1)
15725  {
15726  if(RoutePair.second != AllRoutes->GetFixedRouteAt(31, RoutePair.first).PrefDirSize() - 1) // not last element in existing route so no good
15727  {
15728  if(!Callon)
15729  {
15730  TrainController->StopTTClockMessage(38, "Can't start a route within or at the start of an existing route");
15731  }
15732  Utilities->CallLogPop(263);
15733  return(false);
15734  }
15735  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(32, RoutePair.first).GetFixedPrefDirElementAt(56, RoutePair.second);
15736  if(RouteElement.Conn[RouteElement.XLinkPos] < 0) // last element in existing route but nowhere to go!
15737  {
15738  if(!Callon)
15739  {
15740  TrainController->StopTTClockMessage(39, "No forward connection from this position");
15741  }
15742  Utilities->CallLogPop(264);
15743  return(false);
15744  }
15745  if((RouteElement.Config[RouteElement.XLinkPos] != End) && (AllRoutes->TrackIsInARoute(11, RouteElement.Conn[RouteElement.XLinkPos],
15746  RouteElement.ConnLinkPos[RouteElement.XLinkPos])))
15747  // last element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
15748  {
15749  if(!Callon)
15750  {
15751  TrainController->StopTTClockMessage(40, "Can't start a route at an element that links forward into an existing route");
15752  }
15753  Utilities->CallLogPop(265);
15754  return(false);
15755  }
15756  StartSelectionRouteID = IDInt(AllRoutes->GetFixedRouteAt(162, RoutePair.first).RouteID);
15758  AllRoutes->GetFixedRouteAt(34, RoutePair.first).PrefDirSize() - 1); // last element
15759  StartElement2 = BlankElement; // only use the route element
15761  Utilities->CallLogPop(266);
15762  return(true); // all retained values set
15763  }
15764 
15765  else // selection not in an existing route
15766  {
15767 // check if it's adjacent to start of an an existing route,
15768  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
15769  {
15770  FirstElement = AllRoutes->GetFixedRouteAt(35, a).GetFixedPrefDirElementAt(58, 0);
15771  if((StartElement1.Conn[0] > -1) && (StartElement1.Conn[0] == FirstElement.TrackVectorPosition))
15772  {
15773  if(!Callon)
15774  {
15775  TrainController->StopTTClockMessage(41, "Can't make selection adjacent to start of another route");
15776  }
15777  Utilities->CallLogPop(267);
15778  return(false);
15779  }
15780  if((StartElement1.Conn[1] > -1) && (StartElement1.Conn[1] == FirstElement.TrackVectorPosition))
15781  {
15782  if(!Callon)
15783  {
15784  TrainController->StopTTClockMessage(42, "Can't make selection adjacent to start of another route");
15785  }
15786  Utilities->CallLogPop(268);
15787  return(false);
15788  }
15789  }
15790 // check if it's adjacent to end of an an existing route,
15791  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
15792  {
15794  if(LastElement.Conn[LastElement.XLinkPos] == StartRoutePosition)
15795  {
15796  if(!Callon)
15797  {
15798  TrainController->StopTTClockMessage(43, "Can't start a route adjacent to the end of an existing route");
15799  }
15800  Utilities->CallLogPop(269);
15801  return(false);
15802  }
15803  }
15804  // not in a route or adjacent to start or end of a route
15805  // in this case reset all variable values to -1 & CheckCount to 4
15806  StartElement1.ELink = -1;
15807  StartElement1.ELinkPos = -1;
15808  StartElement1.XLink = -1;
15809  StartElement1.XLinkPos = -1;
15810  StartElement1.EXNumber = -1;
15812  StartElement2 = BlankElement;
15813  SearchVector.push_back(StartElement1);
15814  Utilities->CallLogPop(270);
15815  return(true);
15816  }
15817 }
15818 
15819 // ---------------------------------------------------------------------------
15820 bool TOneRoute::GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
15821 
15822 /*
15823  If Callon true then this routine is called from MainScreenMouseDown2 in InterfaceUnit.cpp to set an unrestricted call-on route - messages are suppressed
15824 
15825  Declare the following integers:-
15826  EndPosition - TrackVectorPosition for the selection;
15827  ReqPosRouteID - for the existing route selected if there is one, set to -1 if not;
15828  Check if selection is a valid track element and set EndPosition.
15829  Cancel if select original start element, then check that not points, bridge or crossover.
15830  Check & fail if a train is present at the selection.
15831  Create & set 2 PrefDirElements EndElement1 & 2 corresponding to the 2 possible PrefDir elements (similar to StartElement1 & 2
15832  in GetNonPreferredRouteStartElement) & make an EXNumber validity check just for safety reasons - the PrefDir values are not used.
15833  No check needed for selection in EveryPrefDir.
15834  Check if selection in an existing route & if so ensure it's the start element and that it doesn't have an 'End' facing the start.
15835  If it is the start of a route set ReqPosRouteID, EndPosition & EndElement1 to the start of route values and blank EndElement2
15836  as don't need it if in a route.
15837  Check if selection adj to start or end of a route and disallow.
15838  Fail if select same route as starting route, though should already have failed earlier if this is so.
15839 
15840  If there's a StartSelectionRouteID then StartElement1 will be set to
15841  the last entry in the selected route so use SearchForNonPreferredRoute to search for the selected end element from this
15842  start element. If succeed then complete the search vector values (since not on a PrefDir) & return true, for Interface
15843  to handle the flashing & time delay. After the delay completes the Interface flasher calls ConvertAndAddNonPreferredRouteSearchVector
15844  to add the new route to the AllRoutesVectorPtr.
15845  If no starting route then StartElement1 only has basic values set & is in the SearchVector, and StartElement2 is blank.
15846  Check if the selected element is adjacent to the starting position and if so set the route to go directly to it (as opposed to
15847  going round a long loop to get to it just because that XLinkPos happens to be chosen first).
15848  If not adjacent then search on the two possible ways out of StartElement1 providing it isn't facing an 'End'. If succeed complete
15849  the search vector values and return.
15850  If not returned yet then have failed to find the required element so return false with no message.
15851 
15852 */
15853 
15854 {
15855 // get EndPosition
15856  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextNonPreferredRouteElement," + AnsiString(HLoc) + "," +
15857  AnsiString(VLoc));
15858  int EndPosition;
15859 
15860  TotalSearchCount = 0;
15861  ReqPosRouteID = IDInt(-1); // for not used
15862  TTrackElement TrackElement;
15863  TPrefDirElement BlankElement;
15864 
15865  if(!(Track->FindNonPlatformMatch(10, HLoc, VLoc, EndPosition, TrackElement))) // return if can't find one
15866  {
15867  Utilities->CallLogPop(271);
15868  return(false);
15869  }
15870 // EndPosition = EndSelectPosition;
15871 // cancel selection if on original start element
15872  if(EndPosition == StartRoutePosition)
15873  {
15874  Utilities->CallLogPop(272);
15875  return(false);
15876  }
15877  if(Track->IsLCAtHV(22, HLoc, VLoc))
15878  {
15879  TrainController->StopTTClockMessage(75, "Can't end a route on a level crossing");
15880  Utilities->CallLogPop(1911);
15881  return(false);
15882  }
15883  if((TrackElement.TrackType == Points) && !Callon)
15884  {
15885  if(!Callon)
15886  {
15887  TrainController->StopTTClockMessage(44, "Can't select points, bridge or crossover when route building");
15888  }
15889 // makes later adjacent route checks too complicated
15890  Utilities->CallLogPop(273);
15891  return(false);
15892  }
15893  if((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
15894  {
15895  if(!Callon)
15896  {
15897  TrainController->StopTTClockMessage(71, "Can't select points, bridge or crossover when route building");
15898  }
15899 // makes later adjacent route checks too complicated
15900  Utilities->CallLogPop(1861);
15901  return(false);
15902  }
15903 // check if train on element
15904  if(TrackElement.TrainIDOnElement > -1)
15905  {
15906  if(!Callon)
15907  {
15908  TrainController->StopTTClockMessage(45, "Can't end a route on a train");
15909  }
15910  Utilities->CallLogPop(274);
15911  return(false);
15912  }
15913 // set the 2 EndElements corresponding to the 2 possible PrefDirs for the selected element (for safety reasons - to ensure EXNumber validity
15914 // check passed)
15915  TPrefDirElement EndElement1(TrackElement); // 1 & 2 for the 2 possible PrefDirs at this location
15916  TPrefDirElement EndElement2(TrackElement);
15917 
15918  EndElement1.TrackVectorPosition = EndPosition;
15919  EndElement2.TrackVectorPosition = EndPosition;
15920  EndElement1.ELinkPos = 0;
15921  EndElement1.XLinkPos = 1;
15922  EndElement1.ELink = EndElement1.Link[0];
15923  EndElement1.XLink = EndElement1.Link[1];
15924  if(!(EndElement1.EntryExitNumber()))
15925  {
15926  throw Exception("Error, No EXNumber for EndElement1 in GetNonPreferredRouteStartElement");
15927  }
15928  EndElement1.CheckCount = 9;
15929  EndElement2.ELinkPos = 1;
15930  EndElement2.XLinkPos = 0;
15931  EndElement2.ELink = EndElement2.Link[1];
15932  EndElement2.XLink = EndElement2.Link[0];
15933  if(!(EndElement2.EntryExitNumber()))
15934  {
15935  throw Exception("Error, No EXNumber for EndElement2 in GetNonPreferredRouteStartElement");
15936  }
15937  EndElement2.CheckCount = 9; // both now set
15938 
15939 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
15940 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
15941 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
15942 
15943  if(EndElement1.HLoc >= StartElement1.HLoc)
15944  {
15946  SearchLimitHighH = EndElement1.HLoc + 15;
15947  }
15948  else
15949  {
15950  SearchLimitLowH = EndElement1.HLoc - 15;
15952  }
15953  if(EndElement1.VLoc >= StartElement1.VLoc)
15954  {
15956  SearchLimitHighV = EndElement1.VLoc + 15;
15957  }
15958  else
15959  {
15960  SearchLimitLowV = EndElement1.VLoc - 15;
15962  }
15963 /* dropped this for v0.4d - prevents ability to set routes for gaps that are widely separated, ok without it as search limited by SearchVector size
15964  check & TotalSearchCounts check
15965  if((abs(EndElement1.HLoc - StartElement1.HLoc) > 120) || (abs(EndElement1.VLoc - StartElement1.VLoc) > 120))
15966  {
15967  if(!Callon) TrainController->StopTTClockMessage(66, "Unable to reach the selected element - too far ahead");
15968  Utilities->CallLogPop(1694);
15969  return false;
15970  }
15971 */
15972 // don't need EveryPrefDir check for NonPreferredRoute
15973 
15974 // check if in an existing route - can't be a 3 or 4 track element so only one TRouteElementPair to be set
15975 // bool InRoute = false;
15977  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(2, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
15978 
15979  if(RoutePair.first > -1)
15980  {
15981  if(RoutePair.second != 0) // not first element in existing route so no good
15982  {
15983  if(!Callon)
15984  {
15985  TrainController->StopTTClockMessage(46, "Can't end a route within or at the end of an existing route");
15986  }
15987  Utilities->CallLogPop(275);
15988  return(false);
15989  }
15990  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(38, RoutePair.first).GetFixedPrefDirElementAt(60, RoutePair.second);
15991 // if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(, RouteElement.Conn[RouteElement.ELinkPos], RouteElement.ELinkPos)))
15992  if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(12, RouteElement.Conn[RouteElement.ELinkPos],
15993  RouteElement.ConnLinkPos[RouteElement.ELinkPos]))) // amended at v1.3.0 - had omitted ConnLinkPos - see above
15994  // first element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
15995  {
15996  if(!Callon)
15997  {
15998  TrainController->StopTTClockMessage(47, "Can't start a route within or at the end of an existing route");
15999  }
16000  Utilities->CallLogPop(276);
16001  return(false);
16002  }
16003  EndElement1 = AllRoutes->GetFixedRouteAt(39, RoutePair.first).GetFixedPrefDirElementAt(61, 0);
16004  EndElement2 = BlankElement; // only need the route element
16005  EndPosition = EndElement1.TrackVectorPosition;
16006  ReqPosRouteID = IDInt(AllRoutes->GetFixedRouteAt(161, RoutePair.first).RouteID);
16007  }
16008 // check if adjacent to start of an existing route and disallow (unless start of existing route is also the start of this route)
16009  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
16010  {
16011  int AdjPosition = AllRoutes->GetFixedRouteAt(40, a).GetFixedPrefDirElementAt(62, 0).TrackVectorPosition;
16012  int AdjLinkPos = AllRoutes->GetFixedRouteAt(219, a).GetFixedPrefDirElementAt(245, 0).ELinkPos; // added at v1.3.1
16013 // if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
16014 // && (AdjPosition != StartRoutePosition))
16015  if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
16016  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
16017  (EndElement1.ConnLinkPos[EndElement1.XLinkPos] == AdjLinkPos) && (AdjPosition != StartRoutePosition))
16018  {
16019  if(!Callon)
16020  {
16021  TrainController->StopTTClockMessage(48, "Can't end a route adjacent to the start of an existing route");
16022  }
16023  Utilities->CallLogPop(277);
16024  return(false);
16025  }
16026 // else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End) &&
16027 // (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (AdjPosition != StartRoutePosition))
16028  else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End)
16029  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
16030  (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (EndElement2.ConnLinkPos[EndElement2.XLinkPos] == AdjLinkPos) &&
16031  (AdjPosition != StartRoutePosition))
16032  {
16033  if(!Callon)
16034  {
16035  TrainController->StopTTClockMessage(49, "Can't end a route adjacent to the start of an existing route");
16036  }
16037  Utilities->CallLogPop(278);
16038  return(false);
16039  }
16040 // check if adjacent to end of a route & disallow (unless end of existing route is the start of this route - i.e. extending route by 1 element)
16042  if((EndOfRouteElement.Config[EndOfRouteElement.XLinkPos] != End) && (EndOfRouteElement.Conn[EndOfRouteElement.XLinkPos] == EndPosition) &&
16043  (EndOfRouteElement.TrackVectorPosition != StartRoutePosition))
16044  {
16045  if(!Callon)
16046  {
16047  TrainController->StopTTClockMessage(50, "Can't end a route adjacent to the end of an existing route");
16048  }
16049  Utilities->CallLogPop(279);
16050  return(false);
16051  }
16052  }
16053 
16054 // check for same route as start element
16056  {
16057  if(!Callon)
16058  {
16059  TrainController->StopTTClockMessage(51, "Can't select same route as started in");
16060  }
16061  Utilities->CallLogPop(280);
16062  return(false);
16063  }
16064 // check for a looping route
16065  if((ReqPosRouteID > -1) && (StartSelectionRouteID > -1))
16066  {
16068  {
16069  if(!Callon)
16070  {
16071  TrainController->StopTTClockMessage(70, "Can't create a route that loops back on itself");
16072  }
16073  Utilities->CallLogPop(1845);
16074  return(false);
16075  }
16076  }
16077 // if there's a StartSelectionRouteID StartElement1 will be set to the last entry in the selected route
16078 // so search from this element.
16079 
16080  TTrackElement &TempElement1 = StartElement1; // this needed to avoid a TTrackElement construction ambiguity in later search function
16081 
16082  if(StartSelectionRouteID > -1)
16083  {
16084  if(SearchForNonPreferredRoute(0, TempElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID))
16085  {
16087  if(PointsToBeChanged(0))
16088  {
16089  PointsChanged = true;
16090  }
16091  Utilities->CallLogPop(281);
16092  return(true);
16093  }
16094  else
16095  {
16096  if(!Callon)
16097  {
16099  }
16100  Utilities->CallLogPop(282);
16101  return(false);
16102  }
16103  }
16104  else // no starting route, so StartElement1 only has basic values set & is in SearchVector, StartElement2 is blank
16105  // search on the 2 ways out of the element, which has to be a 2-ended element
16106  {
16107 // check if selection adjacent to start element and if so use that
16108  if(SearchVector.at(0).Conn[0] == EndPosition)
16109  {
16110  if(SearchForNonPreferredRoute(1, TempElement1, 0, EndPosition, ReqPosRouteID))
16111  {
16113  if(PointsToBeChanged(1))
16114  {
16115  PointsChanged = true;
16116  }
16117  Utilities->CallLogPop(283);
16118  return(true);
16119  }
16120  else
16121  {
16122  if(!Callon)
16123  {
16125  }
16126  Utilities->CallLogPop(284);
16127  return(false);
16128  }
16129  }
16130  else if(SearchVector.at(0).Conn[1] == EndPosition)
16131  {
16132  if(SearchForNonPreferredRoute(2, TempElement1, 1, EndPosition, ReqPosRouteID))
16133  {
16135  if(PointsToBeChanged(2))
16136  {
16137  PointsChanged = true;
16138  }
16139  Utilities->CallLogPop(285);
16140  return(true);
16141  }
16142  else
16143  {
16144  if(!Callon)
16145  {
16147  }
16148  Utilities->CallLogPop(286);
16149  return(false);
16150  }
16151  }
16152  // now start off in the best direction
16153  int BestPos = Track->FindClosestLinkPosition(1, StartRoutePosition, EndPosition); // can only be 0 or 1
16154 
16155  if(SearchVector.at(0).Config[BestPos] != End)
16156  {
16157  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
16158  if(SearchForNonPreferredRoute(3, TempElement1, BestPos, EndPosition, ReqPosRouteID))
16159  {
16161  if(PointsToBeChanged(3))
16162  {
16163  PointsChanged = true;
16164  }
16165  Utilities->CallLogPop(287);
16166  return(true);
16167  }
16168  }
16169  if(SearchVector.at(0).Config[1 - BestPos] != End)
16170  {
16171  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
16172  if(SearchForNonPreferredRoute(4, TempElement1, (1 - BestPos), EndPosition, ReqPosRouteID))
16173  {
16175  if(PointsToBeChanged(4))
16176  {
16177  PointsChanged = true;
16178  }
16179  Utilities->CallLogPop(288);
16180  return(true);
16181  }
16182  }
16183  }
16184  if(!Callon)
16185  {
16187  }
16188  Utilities->CallLogPop(289);
16189  return(false);
16190 }
16191 
16192 // ---------------------------------------------------------------------------
16193 
16194 bool TOneRoute::SearchForNonPreferredRoute(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID)
16195 /*
16196  This is very similar to the preferred route search, but without the need to ensure all elements are in EveryPrefDir.
16197  Returns true for successful search with SearchVector containing the new route elements. Enter with CurrentTrackElement
16198  stored in SearchVector unless it's in an existing route, & XLinkPos set to the link to search on.
16199  Keep a count of entries in SearchVector during the current function call, so that this number can be
16200  erased for an unproductive branch search.
16201  First check (within the loop) whether XLink leads to an End & return false if so.
16202  Create a NextTrackElement from Current & XLinkPos, and a PrefDirElement (SearchElement) from that, setting as many values as
16203  possible. Check if element is already in searchvector (OK if a bridge & earlier entry on different track, but not OK if
16204  any other type of element), already in an existing route (OK if bridge & diff tracks, or start of an expected route), if
16205  train on element (unless a bridge & train on different track), or if element
16206  fouls an existing diagonal route (except if element is a leading point - these checked later).
16207  Then check if found required element. If so save it & return true.
16208  If not the required element check if buffer or continuation, & if so erase all searchvector
16209  & return false. If OK check if a leading point and if so do up to 2 recursive searches for the 2 exits (trying the 'set' exit first),
16210  checking in each case whether the element fouls an existing diagonal route. If fail on both exits erase searchvector & return false.
16211  If not any of above, store element in SearchVector, increment VectorCount, set the new CurrentTrackElement value from the
16212  SearchElement & the new XLinkPos from SearchElement.XLinkPos, then go back to the while loop for the next step in the search.
16213  When return true have 8 items from CheckCount established, only waiting for EXNumber
16214 */
16215 {
16216  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForNonPreferredRoute," + CurrentTrackElement.LogTrack(14) + "," +
16217  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition) + "," + AnsiString() + "," + AnsiString(ReqPosRouteID.GetInt()));
16218  int VectorCount = 0;
16219 
16220 // check for a fouled diagonal for first element. Added for v1.3.2
16221  if((CurrentTrackElement.Link[XLinkPos] == 1) || (CurrentTrackElement.Link[XLinkPos] == 3) || (CurrentTrackElement.Link[XLinkPos] == 7) ||
16222  (CurrentTrackElement.Link[XLinkPos] == 9))
16223  {
16224  if(AllRoutes->DiagonalFouledByRouteOrTrain(8, CurrentTrackElement.HLoc, CurrentTrackElement.VLoc, CurrentTrackElement.Link[XLinkPos]))
16225  {
16226  for(int x = 0; x < VectorCount; x++)
16227  {
16228  SearchVector.erase(SearchVector.end() - 1);
16229  }
16230  Utilities->CallLogPop(2044);
16231  return(false);
16232  }
16233  }
16234  while(true)
16235  {
16236  if(Track->IsLCBarrierFlashingAtHV(2, CurrentTrackElement.HLoc, CurrentTrackElement.VLoc)) // can't set a route through a flashing barrier
16237  {
16238  for(int x = 0; x < VectorCount; x++)
16239  {
16240  SearchVector.erase(SearchVector.end() - 1);
16241  }
16242  Utilities->CallLogPop(1927);
16243  return(false);
16244  }
16245  if(CurrentTrackElement.Config[XLinkPos] == End) // buffers or continuation
16246  {
16247  for(int x = 0; x < VectorCount; x++)
16248  {
16249  SearchVector.erase(SearchVector.end() - 1);
16250  }
16251  Utilities->CallLogPop(290);
16252  return(false);
16253  }
16254  int NextPosition = CurrentTrackElement.Conn[XLinkPos];
16255  TTrackElement NextTrackElement = Track->TrackElementAt(93, NextPosition);
16256  TPrefDirElement SearchElement(NextTrackElement);
16257  SearchElement.TrackVectorPosition = NextPosition;
16258  int NextELinkPos = CurrentTrackElement.ConnLinkPos[XLinkPos];
16259  SearchElement.ELinkPos = NextELinkPos;
16260  SearchElement.ELink = SearchElement.Link[SearchElement.ELinkPos];
16261  int NextXLinkPos;
16262  if(SearchElement.ELinkPos == 0)
16263  {
16264  NextXLinkPos = 1;
16265  }
16266  if(SearchElement.ELinkPos == 1)
16267  {
16268  NextXLinkPos = 0;
16269  }
16270  if(SearchElement.ELinkPos == 2)
16271  {
16272  NextXLinkPos = 3;
16273  }
16274  if(SearchElement.ELinkPos == 3)
16275  {
16276  NextXLinkPos = 2;
16277  }
16278  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
16279  {
16280  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
16281  // but may be buffers, continuation or gap
16282  SearchElement.XLinkPos = NextXLinkPos;
16283  }
16284 // Now have SpeedTag, HLoc, VLoc, TrackVectorPosition, ELink, ELinkPos, and for non-points XLink & XLinkPos
16285 // can't set XLink or XLinkPos yet if the element is a leading point.
16286 
16287 // check if reached an earlier position on search PrefDir (was OK in SearchForPrefDir if entry values different, but not OK for a route)
16288  for(unsigned int x = 0; x < SearchVector.size(); x++)
16289  {
16290  if(SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition)
16291  {
16292  if((SearchElement.TrackType != Bridge) || ((SearchElement.TrackType == Bridge) && (SearchElement.ELink == SearchVector.at(x).ELink)))
16293  // OK if it's a bridge & routes on different tracks
16294  {
16295  for(int x = 0; x < VectorCount; x++)
16296  {
16297  SearchVector.erase(SearchVector.end() - 1);
16298  }
16299  Utilities->CallLogPop(291);
16300  return(false);
16301  }
16302  }
16303  }
16304 
16305 // check if element in an existing route (OK if bridge & diff tracks, or start of an expected route)
16306  TAllRoutes::TRouteElementPair SecondPair;
16308  Track->TrackElementAt(94, SearchElement.TrackVectorPosition).HLoc, Track->TrackElementAt(95, SearchElement.TrackVectorPosition).VLoc, SecondPair);
16309  if(RoutePair.first > -1)
16310  {
16311  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
16312  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(43, RoutePair.first).GetFixedPrefDirElementAt(64,
16313  RoutePair.second).ELinkPos)))
16314  {
16315  // still OK if start of an expected route
16316  if((ReqPosRouteID == IDInt(-1)) || ((int)RoutePair.first != AllRoutes->GetRouteVectorNumber(4, ReqPosRouteID)) || (RoutePair.second != 0))
16317  {
16318  for(int x = 0; x < VectorCount; x++)
16319  {
16320  SearchVector.erase(SearchVector.end() - 1);
16321  }
16322  Utilities->CallLogPop(292);
16323  return(false); // only allow for start of an expected route
16324  }
16325  }
16326  }
16327  if(SecondPair.first > -1) // if reach here & secondpair present then must fail as can't escape both existing routes, but leave check as before anyway
16328  {
16329  // OK if it's a bridge & routes on different tracks
16330  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(44, SecondPair.first).GetFixedPrefDirElementAt(65,
16331  SecondPair.second).ELinkPos)))
16332  {
16333  // still OK if start of an expected route
16334  if((ReqPosRouteID == IDInt(-1)) || ((int)SecondPair.first != AllRoutes->GetRouteVectorNumber(5, ReqPosRouteID)) || (SecondPair.second != 0))
16335  {
16336  for(int x = 0; x < VectorCount; x++)
16337  {
16338  SearchVector.erase(SearchVector.end() - 1);
16339  }
16340  Utilities->CallLogPop(293);
16341  return(false); // only allow for start of an expected route
16342  }
16343  }
16344  }
16345 // check if a train on element, unless a bridge & train on different track
16346 // OK of same train as start element - no, drop this
16347 // if(SearchElement.TrainIDOnElement != StartSelectionTrainID)
16348  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType != Bridge))
16349  {
16350  for(int x = 0; x < VectorCount; x++)
16351  {
16352  SearchVector.erase(SearchVector.end() - 1);
16353  }
16354  Utilities->CallLogPop(294);
16355  return(false);
16356  }
16357  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType == Bridge))
16358  {
16359  if((SearchElement.ELinkPos < 2) && (SearchElement.TrainIDOnBridgeTrackPos01 > -1))
16360  {
16361  for(int x = 0; x < VectorCount; x++)
16362  {
16363  SearchVector.erase(SearchVector.end() - 1);
16364  }
16365  Utilities->CallLogPop(295);
16366  return(false);
16367  }
16368  else if((SearchElement.ELinkPos > 1) && (SearchElement.TrainIDOnBridgeTrackPos23 > -1))
16369  {
16370  for(int x = 0; x < VectorCount; x++)
16371  {
16372  SearchVector.erase(SearchVector.end() - 1);
16373  }
16374  Utilities->CallLogPop(296);
16375  return(false);
16376  }
16377  }
16378 // check for a fouled diagonal (if not leading point - leading point XLink == -1)
16379  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
16380  {
16381  if(AllRoutes->DiagonalFouledByRouteOrTrain(3, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
16382  {
16383  for(int x = 0; x < VectorCount; x++)
16384  {
16385  SearchVector.erase(SearchVector.end() - 1);
16386  }
16387  Utilities->CallLogPop(297);
16388  return(false);
16389  }
16390  }
16391 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
16392 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
16393 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
16395  {
16396  for(int x = 0; x < VectorCount; x++)
16397  {
16398  SearchVector.erase(SearchVector.end() - 1);
16399  }
16400  Utilities->CallLogPop(1689);
16401  return(false);
16402  }
16403 // check if found it
16404  if(SearchElement.TrackVectorPosition == RequiredPosition)
16405  {
16406  if(SearchElement.TrackType == Points) // can only happen for platform element in CallingOnAllowed function
16407  {
16408  if((SearchElement.ELinkPos == 1) || (SearchElement.ELinkPos == 3))
16409  {
16410  SearchElement.XLinkPos = 0; // select the straight track (for the platform)
16411  }
16412  else
16413  {
16414  SearchElement.XLinkPos = 1;
16415  }
16416 // SearchElement.XLink = SearchElement.Link[XLinkPos]; WRONG!! NajamUddin found this error 17/01/11, XLinkPos is the function input parameter, should be SearchElement.XLinkPos
16417  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos]; // corrected for v0.6a
16418  }
16419  SearchVector.push_back(SearchElement);
16420  VectorCount++; // not really needed but include for tidyness
16421  TotalSearchCount++;
16422  Utilities->CallLogPop(298);
16423  return(true);
16424  }
16425 // Not the required element - check if a buffer or continuation
16426  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
16427  {
16428  for(int x = 0; x < VectorCount; x++)
16429  {
16430  SearchVector.erase(SearchVector.end() - 1);
16431  }
16432  Utilities->CallLogPop(299);
16433  return(false);
16434  }
16435 // check if SearchVector exceeds a size of 150
16436  if(SearchVector.size() > 150)
16437  {
16438  for(int x = 0; x < VectorCount; x++)
16439  {
16440  SearchVector.erase(SearchVector.end() - 1);
16441  }
16442  Utilities->CallLogPop(1421);
16443  return(false);
16444  }
16445 // check if reached a leading point
16446  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead))
16447  {
16448 // XLink set to points 'set' position - Attribute == 0, SearchPos1 = 1 & SearchPos2 = 3; Attribute == 1, SearchPos1 = 3 & SearchPos2 = 1;
16449  int SearchPos1 = SearchElement.Attribute + 1;
16450  int SearchPos2;
16451  if(SearchPos1 == 2)
16452  {
16453  SearchPos1++;
16454  }
16455  if(SearchPos1 == 1)
16456  {
16457  SearchPos2 = 3;
16458  }
16459  else
16460  {
16461  SearchPos2 = 1;
16462  }
16463 // push element with XLink set to position [SearchPos1]
16464  SearchElement.XLink = SearchElement.Link[SearchPos1];
16465  SearchElement.XLinkPos = SearchPos1;
16466 // check for a fouled diagonal for leading point for XLinkPos == SearchPos1)
16467  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
16468  {
16469  if(AllRoutes->DiagonalFouledByRouteOrTrain(4, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
16470  {
16471  for(int x = 0; x < VectorCount; x++)
16472  {
16473  SearchVector.erase(SearchVector.end() - 1);
16474  }
16475  Utilities->CallLogPop(300);
16476  return(false);
16477  }
16478  }
16479  SearchVector.push_back(SearchElement);
16480  VectorCount++;
16481  TotalSearchCount++;
16482 // recursive search at XLinkPos of SearchPos1 (i.e. 'set' trailing exit)
16483 // Note that NextTrackElement is the TTrackElement that the TPrefDirElement SearchElement is constructed from. Can't use SearchElement in the
16484 // recursive search as has to be a TTrackElement for non-preferred route searches
16485  if(SearchForNonPreferredRoute(6, NextTrackElement, SearchPos1, RequiredPosition, ReqPosRouteID))
16486  {
16487  Utilities->CallLogPop(301);
16488  return(true);
16489  }
16490  else
16491  {
16492 // remove leading point with XLinkPos [SearchPos1]
16493  SearchVector.erase(SearchVector.end() - 1);
16494  VectorCount--;
16495 // push element with XLink set to position [SearchPos2]
16496  SearchElement.XLink = SearchElement.Link[SearchPos2];
16497  SearchElement.XLinkPos = SearchPos2;
16498 // check for a fouled diagonal for leading point for XLinkPos == SearchPos2)
16499  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
16500  {
16501  if(AllRoutes->DiagonalFouledByRouteOrTrain(5, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
16502  {
16503  for(int x = 0; x < VectorCount; x++)
16504  {
16505  SearchVector.erase(SearchVector.end() - 1);
16506  }
16507  Utilities->CallLogPop(302);
16508  return(false);
16509  }
16510  }
16511  SearchVector.push_back(SearchElement);
16512  VectorCount++;
16513  TotalSearchCount++;
16514 // recursive search at XLinkPos of SearchPos2 (i.e. 'unset' trailing exit)
16515  if(SearchForNonPreferredRoute(7, NextTrackElement, SearchPos2, RequiredPosition, ReqPosRouteID))
16516  {
16517  Utilities->CallLogPop(303);
16518  return(true);
16519  }
16520  else
16521  {
16522  for(int x = 0; x < VectorCount; x++)
16523  {
16524  SearchVector.erase(SearchVector.end() - 1);
16525  }
16526  Utilities->CallLogPop(304);
16527  return(false);
16528  }
16529  }
16530  } // if leading point
16531 
16532 // here if ordinary element, push it, inc VectorCount & update CurrentTrackElement
16533 // ready for next element on route
16534  SearchVector.push_back(SearchElement);
16535  VectorCount++;
16536  TotalSearchCount++;
16537  CurrentTrackElement = SearchElement;
16538  XLinkPos = SearchElement.XLinkPos; // wasn't a leading point so XLinkPos defined
16539  } // while(true)
16540 }
16541 
16542 // ---------------------------------------------------------------------------
16543 
16545 
16546 /*
16547  This function is developed from ConvertPrefDirSearchVector, to deal with search elements not
16548  having all values set (since not necessarily on PrefDirs).
16549  Enter with SearchVector established, return if empty. The first element may not have its ELink & XLink etc set
16550  (if it was the start), so these are checked first and set if necessary. All elements now have
16551  all but EXNumber set, so the CheckCount is set to 8 to cover all but EXNumber, and that is then set
16552  for all elements (unless validity check fails) and CheckCount incremented. Finally SetRouteSearchVectorGraphics() is called
16553  to set the route colour and direction graphics.
16554 */
16555 
16556 {
16557  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRemainingSearchVectorValues");
16558  if(SearchVector.size() == 0)
16559  {
16560  throw Exception("Error, SearchVector empty");
16561  }
16562 // first SearchElement may have ELink & XLink not set if entered in GetStart.... i.e if it wasn't already in a route
16563 // hence need to examine and update it if necessary
16564  TPrefDirElement SecondElement;
16565 
16566  if(SearchVector.size() > 1) // if search vector only a single element then first element must have been in a route, and in this case
16567  // all data members will have been set in SearchForNonPreferredRoute except for EXNumber.
16568  // need above check or SecondElement will fail
16569  {
16570  SecondElement = SearchVector.at(1);
16571  // SearchVector.at(0) ELink & XLink not set if was first element in route; XLink also not set if was a leading point though can't be for a route
16572  for(int x = 0; x < 4; x++)
16573  {
16574  if(SearchVector.at(0).Conn[x] == SecondElement.TrackVectorPosition)
16575  {
16576  if(SearchVector.at(0).XLink == -1) // i.e. not set
16577  {
16578  SearchVector.at(0).XLink = SearchVector.at(0).Link[x];
16579  SearchVector.at(0).XLinkPos = x;
16580  }
16581  int ELinkPos;
16582  if(SearchVector.at(0).XLinkPos == 0)
16583  {
16584  ELinkPos = 1; // use actual value rather than 'x' as may be a gap with both ends
16585  }
16586  // linked to 1st searchvector element, & if XLink was set then x may not correspond
16587  if(SearchVector.at(0).XLinkPos == 1)
16588  {
16589  ELinkPos = 0;
16590  }
16591  if(SearchVector.at(0).XLinkPos == 2)
16592  {
16593  ELinkPos = 3;
16594  }
16595  if(SearchVector.at(0).XLinkPos == 3)
16596  {
16597  ELinkPos = 2;
16598  }
16599  if(SearchVector.at(0).ELink == -1) // because was start element, & can't be points, but could be a gap
16600  {
16601  SearchVector.at(0).ELink = SearchVector.at(0).Link[ELinkPos];
16602  SearchVector.at(0).ELinkPos = ELinkPos;
16603  }
16604  break; // no point going any further
16605  }
16606  }
16607  }
16608  for(unsigned int x = 0; x < SearchVector.size(); x++)
16609  {
16610  SearchVector.at(x).CheckCount = 8; // to account for all but EXNumber
16611 // set EXNumber
16612  if(!(SearchVector.at(x).EntryExitNumber()))
16613  {
16614  throw Exception("Error in EntryExitNumber 3");
16615  }
16616  SearchVector.at(x).CheckCount++;
16617 // all values now incorporated
16618  }
16619 
16620  SetRouteSearchVectorGraphics(5, false, false); // change graphic colour to the route colour
16621 // This function is only called here for nonsignals routes, so AutoSigsFlag & PrefDirRoute both false
16622 // PrefDir is validated in ConvertAndAddNonPreferredRouteSearchVector
16623  Utilities->CallLogPop(305);
16624 }
16625 
16626 // ---------------------------------------------------------------------------
16627 
16629 
16630 /*
16631  This function is very similar to ConvertAndAddPreferredRouteSearchVector except that the route in SearchVector can't be an
16632  AutoSigsRoute.
16633  Action varies depending on whether it is a completely new route, or an extension of an existing route at the
16634  beginning or the end.
16635  Ignore if SearchVector empty, and check that all the new elements in SearchVector are valid.
16636  Check if route end selection is in an existing route (ReqPosRouteID > -1), if so and existing route is non-autosigs
16637  add its elements to the SearchVector then delete the route, decrementing StartSelectionRouteNumber if the RequPosRouteNumber was
16638  less than StartSelectionRouteID. If existing route is AutoSigs then the final search element is dropped from the SearchVector,
16639  since the new route will end adjacent to the AutoSigs route, and the existing route is left as it is.
16640  Note that a single route cannot contain both AutoSig & non-AutoSig elements, each route of AutoSig elements
16641  has its own identity. A single route can however have a mixture of Unrestricted and PreferredRoute elements
16642 
16643  Check if StartSelectionRouteID set (extending an existing route) and if so and if existing route non-autosig, then add the new route
16644  to the existing route (start element not stored in searchvector), call SetRoutePoints & SetRouteSignals for the extended route and return.
16645  If the existing route is autosig, then leave the existing route as it is and continue as for routes that aren't linked to an existing
16646  route at the start.
16647 
16648  Check the validity of the route in SearchVector, and create a new route using StoreOneRoute. Finally call SetRoutePoints & SetRouteSignals
16649  for the new route and return.
16650 */
16651 
16652 {
16653  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertAndAddNonPreferredRouteSearchVector," +
16654  AnsiString(ReqPosRouteID.GetInt()));
16655  if(SearchVector.size() < 1)
16656  {
16657  Utilities->CallLogPop(306);
16658  return;
16659  }
16660  PrefDirVector = SearchVector; // this copy is to validate the vector up to this point,
16661  if(!ValidatePrefDir(6))
16662  {
16663  Utilities->CallLogPop(307);
16664  return;
16665  }
16666  TAllRoutes::TLockedRouteClass LockedRouteObject;
16667 
16669  unsigned int TruncatePrefDirPosition = 0;
16670 
16671  if(ReqPosRouteID > -1) // Note that ReqPosRouteID != StartSelectionRouteID as would have failed in GetNextRouteElement
16672 /* if have ReqPosRouteID:
16673  if existing route non-autosig, then add the old route to the SearchVector then delete the old route
16674  if existing route autosig, drop the final search element in the new route, leave the existing route as it is,
16675  then enter the new route into the AllRoutesVector
16676 */
16677  {
16679  {
16680  for(unsigned int x = 1; x < AllRoutes->GetFixedRouteAtIDNumber(46, ReqPosRouteID).PrefDirSize();
16681  x++) // start at 1 as first element already in SearchVector
16682  {
16684  }
16685  // note that route numbers in map adjusted when ReqPos route cleared
16687  // create a new locked route object (apart from RouteNumber) if required, for use later (LockedRouteFoundDuringRouteBuilding
16688  // set during ClearRouteDuringRouteBuildingAt)
16690  {
16693  LockedRouteObject.LastXLinkPos = AllRoutes->LockedRouteLastXLinkPos;
16694  LockedRouteObject.LockStartTime = AllRoutes->LockedRouteLockStartTime;
16695  }
16696  }
16698  {
16699  SearchVector.pop_back();
16700  }
16701  }
16702  if(StartSelectionRouteID > -1)
16703 /* if have StartSelectionRouteID:
16704  if existing route non-autosig, then add the new route to the existing route (start element not stored in searchvector)
16705  if existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
16706 */
16707  {
16709  // need to test because may have been removed by a train moving in the wrong direction between first and last route selections - added at v1.3.1
16710  {
16712  {
16713  int RouteNumber = AllRoutes->GetRouteVectorNumber(1, StartSelectionRouteID);
16714  for(unsigned int x = 0; x < SearchVector.size(); x++)
16715  {
16717  RouteNumber, GetFixedSearchElementAt(7, x));
16718  // find & store locked route truncate position in PrefDirVector for later use
16720  {
16721  if(GetFixedSearchElementAt(16, x).TrackVectorPosition == int(AllRoutes->LockedRouteTruncateTrackVectorPosition))
16722  {
16723  TruncatePrefDirPosition = AllRoutes->GetFixedRouteAt(176, RouteNumber).PrefDirSize() - 1;
16724  }
16725  }
16726  }
16728  {
16729  throw Exception("Failed to validate extended route for nonpreferred route");
16730  }
16733  AllRoutes->GetModifiableRouteAtIDNumber(9, StartSelectionRouteID).SetLCChangeValues(2, false); // PrefDirRoute is false
16734  // now add the reinstated locked route if required and set signals accordingly
16735  // shouldn't ever need to access this as the train that has caused the locked route will be ahead of the route to be added,
16736  // and it will have removed the route elements that it is standing on, but include in case there's some obscure condition
16737  // that I haven't thought of
16739  {
16740  LockedRouteObject.RouteNumber = RouteNumber;
16741  AllRoutes->LockedRouteVector.push_back(LockedRouteObject);
16742  // now reset the signals for the locked route
16743  AllRoutes->SetAllRearwardsSignals(12, 0, RouteNumber, TruncatePrefDirPosition);
16744  for(int c = AllRoutes->GetFixedRouteAt(177, RouteNumber).PrefDirSize() - 1; c >= (int)TruncatePrefDirPosition;
16745  c--) // must use int for >= test to succeed when TruncatePrefDirPosition == 0
16746  {
16747  // return all signals to red in route section to be truncated
16748  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(178, RouteNumber).PrefDirVector.at(c);
16749  TTrackElement & TrackElement = Track->TrackElementAt(813, PrefDirElement.TrackVectorPosition);
16750  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
16751  {
16752  TrackElement.Attribute = 0;
16753  Track->PlotSignal(11, TrackElement, Display);
16754  Display->PlotOutput(115, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
16755  Display->PlotOutput(116, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
16756  }
16757  }
16758  }
16759  AllRoutes->CheckMapAndRoutes(3); // test
16760  Utilities->CallLogPop(308);
16761  return;
16762  }
16763  }
16764  else
16765  {
16767  }
16768 // if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
16769 // hence nothing to do here
16770  }
16771  PrefDirVector = SearchVector; // copy again prior to storing as a route as SearchVector may have been extended
16772  if(!ValidatePrefDir(8)) // validate PrefDir for all new route elements
16773  {
16774  throw Exception("Failed to validate single route for nonpreferred route");
16775  }
16776  AllRoutes->StoreOneRoute(2, this);
16777  AllRoutes->GetModifiableRouteAt(6, AllRoutes->AllRoutesSize() - 1).SetRoutePoints(3); // new addition
16778  AllRoutes->GetModifiableRouteAt(17, AllRoutes->AllRoutesSize() - 1).SetRouteSignals(7); // new addition
16779  AllRoutes->GetModifiableRouteAt(19, AllRoutes->AllRoutesSize() - 1).SetLCChangeValues(3, false); // ConsecSignalsRoute is false
16780  AllRoutes->CheckMapAndRoutes(4); // test
16781  Utilities->CallLogPop(309);
16782 }
16783 
16784 // ---------------------------------------------------------------------------
16785 
16786 void TOneRoute::SetRoutePoints(int Caller) const
16787 /*
16788  Examine each set of points in the route to see if entry or exit is via the straight or diverging trailing
16789  link, and set the attribute accordingly (don't need to worry about linked routes, points in those will have been set
16790  when they were created.
16791 */
16792 {
16793  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRoutePoints");
16794  if(!PrefDirVector.empty())
16795  {
16796  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.end() - 1); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
16797  {
16798  if((PrefDirPtr->TrackType == Points) && ((PrefDirPtr->ELinkPos == 1) || (PrefDirPtr->XLinkPos == 1))) // 1=straight trailing
16799  {
16800  Track->TrackElementAt(96, PrefDirPtr->TrackVectorPosition).Attribute = 0; // 0=straight
16801  Track->PlotPoints(3, Track->TrackElementAt(97, PrefDirPtr->TrackVectorPosition), Display, false);
16802  }
16803  if((PrefDirPtr->TrackType == Points) && ((PrefDirPtr->ELinkPos == 3) || (PrefDirPtr->XLinkPos == 3))) // 3=diverging trailing
16804  {
16805  Track->TrackElementAt(98, PrefDirPtr->TrackVectorPosition).Attribute = 1; // 1=diverging
16806  Track->PlotPoints(4, Track->TrackElementAt(99, PrefDirPtr->TrackVectorPosition), Display, false);
16807  }
16808  }
16809  }
16810  Utilities->CallLogPop(327);
16811 }
16812 
16813 // ---------------------------------------------------------------------------
16814 
16815 void TOneRoute::SetRouteSignals(int Caller) const
16816 /* Used for new train additions in AddTrain and in route setting
16817  Set the signals as follows:-
16818  First check whether there is a linked forward route, and if so use FindForwardTargetSignalAttribute to work along it from the start
16819  until find a train (return Attribute = 0 & NextForwardLinkedRouteNumber = -1), a buffer (return Attribute = 1 &
16820  NextForwardLinkedRouteNumber = -1), a continuation (return Attribute = 3 & NextForwardLinkedRouteNumber = -1) or a forward-facing
16821  signal. If find a signal its attribute value + 1 up to a maximum value of 3 is returned & NextForwardLinkedRouteNumber = -1.
16822  The above Attribute values represent the 'target' attribute, from which all rearwards signals in turn in the new route are set,
16823  the first using the returned attribute value and subsequent ones incrementing the Attribute up to a maximum of 3. All the foregoing
16824  return true, as does finding none of the above and no onward linked forward route (NextForwardLinkedRouteNumber = -1). If none
16825  of the foregoing are found but there is a further forward linked forward route then the function returns false with
16826  NextForwardLinkedRouteNumber = the next forward linked route number, to allow that to be examined similarly, and Attribute = 0.
16827 
16828  When the target Attribute is found (will be 0 if no forward linked route), then SetAllRearwardsSignals is used to work back from
16829  the end of the route setting each forward-facing signal one step nearer green as described above, until either reach the end of all
16830  linked rearwards routes or find a train. If find a train in the current route then signals behind it (and behind any other trains
16831  in the current route) are set appropriately (including in linked rear routes), but if find a train in a linked rear route then no
16832  further signals are set. If there is no forward linked route and the front end of the current route is a buffer then
16833  SetAllRearwardsSignals (in its call to SetRearwardsSignalsReturnFalseForTrain) treats it as a red signal, and if a continuation,
16834  as a green signal.
16835 */
16836 {
16837  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteSignals");
16838  if(!PrefDirVector.empty())
16839  {
16840  // get target Attribute value, check first if there is a forward linked route
16841  TPrefDirElement LastElement = GetFixedPrefDirElementAt(185, PrefDirSize() - 1);
16842  TPrefDirElement FirstElement = GetFixedPrefDirElementAt(186, 0);
16843  int ForwardLinkedRouteNumber, Attribute = 0;
16844  if(LastElement.Conn[LastElement.XLinkPos] > -1)
16845  // Note that LastElement can't be points but can be linked to points
16846  {
16847  if(AllRoutes->GetRouteTypeAndNumber(16, LastElement.Conn[LastElement.XLinkPos], LastElement.ConnLinkPos[LastElement.XLinkPos],
16848  ForwardLinkedRouteNumber) != TAllRoutes::NoRoute)
16849  {
16850  if(ForwardLinkedRouteNumber > -1)
16851  {
16852  int NextForwardLinkedRouteNumber = -1;
16853  while(!(AllRoutes->GetFixedRouteAt(171, ForwardLinkedRouteNumber).FindForwardTargetSignalAttribute(1, NextForwardLinkedRouteNumber,
16854  Attribute)))
16855  {
16856  ForwardLinkedRouteNumber = NextForwardLinkedRouteNumber;
16857  }
16858  // if find a train before a signal then Attribute = 0, else if find end of route is a buffer then Attribute = 1, or a continuation then
16859  // Attribute = 3, else if find signal then Attribute = (signal attribute + 1) up to a max value of 3. All these return true, if find a
16860  // forward linked route then the routenumber is set in NextForwardLinkedRouteNumber, Attribute = 0 & returns false.
16861  }
16862  }
16863  }
16864  int RouteNumber;
16865  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(15, GetFixedPrefDirElementAt(187, 0).TrackVectorPosition,
16866  GetFixedPrefDirElementAt(193, 0).XLinkPos, RouteNumber);
16867  if(RouteType != TAllRoutes::NoRoute)
16868  // it will be, above only used to get RouteNumber, can choose any element in the route so use GetFixedPrefDirElementAt
16869  {
16870  AllRoutes->SetAllRearwardsSignals(8, Attribute, RouteNumber, PrefDirSize() - 1);
16871  }
16872  }
16873  Utilities->CallLogPop(1720);
16874 }
16875 
16876 // ---------------------------------------------------------------------------
16877 
16878 bool TOneRoute::PointsToBeChanged(int Caller) const
16879 {
16880  // true if at any point in SearchVector points have to be changed
16881  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PointsToBeChanged");
16882  if(!SearchVector.empty())
16883  {
16884  for(TPrefDirVectorConstIterator SearchPtr = SearchVector.begin(); SearchPtr != SearchVector.end(); SearchPtr++)
16885  {
16886  if((SearchPtr->TrackType == Points) && ((SearchPtr->ELinkPos == 1) || (SearchPtr->XLinkPos == 1))) // 1=straight trailing
16887  {
16888  if(Track->TrackElementAt(752, SearchPtr->TrackVectorPosition).Attribute != 0) // 0=straight or LH
16889  {
16890  Utilities->CallLogPop(1717);
16891  return(true);
16892  }
16893  }
16894  if((SearchPtr->TrackType == Points) && ((SearchPtr->ELinkPos == 3) || (SearchPtr->XLinkPos == 3))) // 3=diverging trailing
16895  {
16896  if(Track->TrackElementAt(753, SearchPtr->TrackVectorPosition).Attribute != 1) // 1=diverging or RH
16897  {
16898  Utilities->CallLogPop(1718);
16899  return(true);
16900  }
16901  }
16902  }
16903  }
16904  Utilities->CallLogPop(1719);
16905  return(false);
16906 }
16907 
16908 // ---------------------------------------------------------------------------
16909 
16910 bool TOneRoute::FindForwardTargetSignalAttribute(int Caller, int &NextForwardLinkedRouteNumber, int &Attribute) const
16911 /*
16912  Works forward through the route until finds:-
16913  (a) a train - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
16914  (b) end of route at buffers - Attribute = 1, NextForwardLinkedRouteNumber = -1 & returns true;
16915  (c) end of route at continuation - Attribute = 3, NextForwardLinkedRouteNumber = -1 & returns true;
16916  (d) level crossing with barriers not down - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
16917  (e) forward-facing signal - Attribute = 1 + signal attribute (max value of 3), NextForwardLinkedRouteNumber = -1 & returns true;
16918  (f) end of route not at any of foregoing and with no linked forward route - Attribute = 0, NextForwardLinkedRouteNumber = -1 &
16919  returns true;
16920  (g) linked forward route - Attribute = 0, NextForwardLinkedRouteNumber = the routenumber of the forward route & returns false.
16921 */
16922 {
16923  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindForwardTargetSignalAttribute");
16924  Attribute = 0;
16925  NextForwardLinkedRouteNumber = -1;
16926  for(unsigned int x = 0; x < PrefDirSize(); x++)
16927  {
16928  int TrainID = Track->TrackElementAt(100, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnElement;
16929  if(PrefDirVector.at(x).TrackType == Bridge)
16930  {
16931  if(PrefDirVector.at(x).XLinkPos < 2)
16932  {
16933  TrainID = Track->TrackElementAt(101, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnBridgeTrackPos01;
16934  }
16935  else
16936  {
16937  TrainID = Track->TrackElementAt(102, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnBridgeTrackPos23;
16938  }
16939  }
16940  if(TrainID != -1)
16941  {
16942  Utilities->CallLogPop(328);
16943  return(true);
16944  }
16945  if(PrefDirVector.at(x).TrackType == Buffers)
16946  {
16947  Attribute = 1;
16948  Utilities->CallLogPop(329);
16949  return(true);
16950  }
16951  if(PrefDirVector.at(x).TrackType == Continuation)
16952  {
16953  Attribute = 3;
16954  Utilities->CallLogPop(330);
16955  return(true);
16956  }
16957  if(Track->IsLCAtHV(42, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc))
16958  {
16959  if(!Track->IsLCBarrierDownAtHV(3, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc))
16960  {
16961  Attribute = 0;
16962  Utilities->CallLogPop(1950);
16963  return(true);
16964  }
16965  }
16966  if(PrefDirVector.at(x).Config[PrefDirVector.at(x).XLinkPos] == Signal)
16967  {
16968  Attribute = Track->TrackElementAt(103, PrefDirVector.at(x).TrackVectorPosition).Attribute + 1;
16969  if(Attribute > 3)
16970  {
16971  Attribute = 3;
16972  }
16973  Utilities->CallLogPop(331);
16974  return(true);
16975  }
16976  if(x == PrefDirSize() - 1)
16977  {
16978  TPrefDirElement LastElement = PrefDirVector.at(x);
16979  if(LastElement.Conn[LastElement.XLinkPos] > -1)
16980  {
16981  if(AllRoutes->GetRouteTypeAndNumber(2, LastElement.Conn[LastElement.XLinkPos],
16982  Track->GetNonPointsOppositeLinkPos(LastElement.ConnLinkPos[LastElement.XLinkPos]), NextForwardLinkedRouteNumber) != TAllRoutes::NoRoute)
16983  {
16984  Attribute = 0;
16985  Utilities->CallLogPop(332);
16986  return(false);
16987  }
16988  }
16989  }
16990  }
16991  Utilities->CallLogPop(333);
16992  return(true);
16993 }
16994 
16995 // ---------------------------------------------------------------------------
16996 
16997 bool TOneRoute::SetRearwardsSignalsReturnFalseForTrain(int Caller, int &Attribute, int PrefDirVectorStartPosition) const
16998 /*
16999  This function is only called by TAllRoutes::SetAllRearwardsSignals.
17000 
17001  Enter with Attribute set to the value to be used (unless modified by the initial forward search - see later) for the first rearwards
17002  signal found, and with PrefDirVectorStartPosition set to the position in PrefDirVector to begin the search. BUT, don't begin with the
17003  rearward search, first search forwards from the PrefDirVectorStartPosition in case the end of the route is a buffer or continuation, and
17004  modify the Attribute accordingly UNLESS (a) train present between PrefDirVectorStartPosition & end; (b) route in
17005  ContinuationAutoSigVector (i.e. train has exited the route at a continuation but it is still affecting the signals), or (c) truncating
17006  a route.
17007 
17008  Having received or modified Attribute as above, work backwards from the PrefDirVectorStartPosition until find a train - return false, or a
17009  signal. If find a signal set its Attribute to the current Attribute value up to a maximum of 3, and replot the signal as well as
17010  the required route and direction (if required) graphics, then increment Attribute up to a max. of 3 [addition at v2.9.2: if signal or element beyond
17011  it is in a locked route then set signal to red & change Attribute to 0 - this fault reported by Simon Banham 21/07/21 as an image]. and continue working
17012  backwards for the next signal (or train - return false as before) and so on. On completion Attribute is passed back from the function as a
17013  reference. If no train is found before the beginning of the route is reached the function returns true
17014 
17015  In setting signals skip the first position if it's a signal and if truncating - otherwise the truncated signal counts as the first red
17016  and the next rearwards signal becomes yellow, although it's the first in the route
17017 */
17018 {
17019  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRearwardsSignalsReturnFalseForTrain," + AnsiString(Attribute) + "," +
17020  AnsiString(PrefDirVectorStartPosition));
17021  Graphics::TBitmap *EXGraphicPtr = RailGraphics->bmTransparentBgnd; // default values
17022  Graphics::TBitmap *EntryDirectionGraphicPtr = RailGraphics->bmTransparentBgnd;
17023 // if no train between end of route and PrefDirVectorStartPosition, route not in ContinuationAutoSigVector
17024 // & not truncating a route, then Attribute can be modified if end is buffers or continuation
17025  bool SkipContinuationAndBufferAttributeChange = false;
17026 
17027  if(!PrefDirVector.empty())
17028  {
17029  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.begin() + PrefDirVectorStartPosition); PrefDirPtr < PrefDirVector.end(); PrefDirPtr++)
17030  {
17031  int TrainID = Track->TrackElementAt(104, PrefDirPtr->TrackVectorPosition).TrainIDOnElement;
17032  if(PrefDirPtr->TrackType == Bridge)
17033  {
17034  if(PrefDirPtr->XLinkPos < 2)
17035  {
17036  TrainID = Track->TrackElementAt(105, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeTrackPos01;
17037  }
17038  else
17039  {
17040  TrainID = Track->TrackElementAt(106, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeTrackPos23;
17041  }
17042  }
17043  if(TrainID != -1)
17044  {
17045  SkipContinuationAndBufferAttributeChange = true;
17046  break;
17047  }
17048  }
17049 
17052  {
17053  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.begin(); AutoSigVectorIT < TrainController->ContinuationAutoSigVector.end();
17054  AutoSigVectorIT++)
17055  {
17056  if(!AllRoutes->AllRoutesVector.empty())
17057  {
17058  if((&AllRoutes->AllRoutesVector.front() + AutoSigVectorIT->RouteNumber) == this)
17059  {
17060  SkipContinuationAndBufferAttributeChange = true;
17061  break;
17062  }
17063  }
17064  }
17065  }
17067  {
17068  SkipContinuationAndBufferAttributeChange = true;
17069  }
17070  if(!SkipContinuationAndBufferAttributeChange)
17071  {
17072  if(PrefDirVector.back().TrackType == Buffers)
17073  {
17074  Attribute = 1; // treat buffer as red signal
17075  }
17076  if(PrefDirVector.back().TrackType == Continuation)
17077  {
17078  Attribute = 3; // treat continuation as a green signal
17079  }
17080  }
17081  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.begin() + PrefDirVectorStartPosition); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
17082  {
17083  int TrainID = Track->TrackElementAt(107, PrefDirPtr->TrackVectorPosition).TrainIDOnElement;
17084  if(PrefDirPtr->TrackType == Bridge)
17085  {
17086  if(PrefDirPtr->XLinkPos < 2)
17087  {
17088  TrainID = Track->TrackElementAt(108, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeTrackPos01;
17089  }
17090  else
17091  {
17092  TrainID = Track->TrackElementAt(109, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeTrackPos23;
17093  }
17094  }
17095  if(TrainID != -1)
17096  {
17097  Utilities->CallLogPop(334);
17098  return(false);
17099  }
17100  // if find an LC that is closed to trains (or flashing - may be extending an earlier route with flashing LCs) then reset
17101  // the attribute to 0 so first signal behind the LC is red
17102  if(Track->IsLCAtHV(20, PrefDirPtr->HLoc, PrefDirPtr->VLoc))
17103  {
17104  if(!Track->IsLCBarrierDownAtHV(1, PrefDirPtr->HLoc, PrefDirPtr->VLoc))
17105  {
17106  Attribute = 0;
17107  }
17108  }
17109 // now set signals, but skip the first position if it's a signal on an unrestricted route and truncating - otherwise the truncated signal
17110 // counts as the first red and the next rearwards signal becomes yellow, although it's the first in the route
17111  if(PrefDirPtr->Config[PrefDirPtr->XLinkPos] == Signal)
17112  {
17113  if((!AllRoutes->RouteTruncateFlag) || (PrefDirPtr != (PrefDirVector.begin() + PrefDirVectorStartPosition)) || PrefDirPtr->AutoSignals ||
17114  PrefDirPtr->PrefDirRoute)
17115  {
17116 //new section at v2.9.2 to check for pref dir element in a locked route, and if so set Attribute to 0 (red). When emerge from locked route Attribute
17117 //still 0 so first signal behind it also stays red. After that Attribute goes back to normal.
17118  int LockedVecNum = 0; //not used
17119  TPrefDirElement DummyPrefDir; //not used
17120  bool KeepAttributeAt0ForLockedRoute = false;
17121  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(15, PrefDirPtr->TrackVectorPosition, PrefDirPtr->XLinkPos, DummyPrefDir,
17122  LockedVecNum))
17123  {
17124  Attribute = 0;
17125  KeepAttributeAt0ForLockedRoute = true;
17126  }
17127 //end of addition
17128  if(Attribute < 3)
17129  {
17130  Track->TrackElementAt(110, PrefDirPtr->TrackVectorPosition).Attribute = Attribute;
17131  }
17132  else
17133  {
17134  Track->TrackElementAt(111, PrefDirPtr->TrackVectorPosition).Attribute = 3; // green
17135  }
17136  Track->PlotSignal(1, Track->TrackElementAt(112, PrefDirPtr->TrackVectorPosition), Display);
17137  if(AllRoutes->GetRouteTypeAndGraphics(1, PrefDirPtr->TrackVectorPosition, PrefDirPtr->XLinkPos, EXGraphicPtr,
17138  EntryDirectionGraphicPtr) != TAllRoutes::NoRoute)
17139  {
17140  Display->PlotOutput(16, Track->TrackElementAt(113, PrefDirPtr->TrackVectorPosition).HLoc * 16,
17141  Track->TrackElementAt(114, PrefDirPtr->TrackVectorPosition).VLoc * 16, EXGraphicPtr);
17142  Display->PlotOutput(17, Track->TrackElementAt(115, PrefDirPtr->TrackVectorPosition).HLoc * 16,
17143  Track->TrackElementAt(116, PrefDirPtr->TrackVectorPosition).VLoc * 16, EntryDirectionGraphicPtr);
17144  }
17145  if((Attribute < 3) && !KeepAttributeAt0ForLockedRoute)
17146  {
17147  Attribute++;
17148  }
17149  Display->Update(); // update after recent plots
17150  }
17151  }
17152  }
17153  }
17154  Utilities->CallLogPop(335);
17155  return(true);
17156 }
17157 
17158 // ---------------------------------------------------------------------------
17159 
17160 void TOneRoute::GetRouteTruncateElement(int Caller, int HLoc, int VLoc, bool PrefDirRoute, TTruncateReturnType &ReturnFlag)
17161 /*
17162  Examines the route to see whether the element at H & V is in the route, and if not returns a ReturnFlag value of NotInRoute.
17163  If it is in a route but the element selected is invalid, then a message is given and returns with a ReturnFlag value of
17164  InRouteFalse. Otherwise the route is truncated at and including the element that matches H & V with a ReturnFlag value of InRouteTrue.
17165  Selection invalid if select a bridge; trying to leave a single element; last element to be left
17166  not a signal (for PrefDirRoute or has AutoSigsFlag set); last element to be left a bridge, points or crossover (for not
17167  PrefDirRoute & AutoSigsFlag not set), or part of route locked. Check if a train approaching or occupying route and lock route
17168  if required after offering the user the choice to continue or not. Then SetAllRearwardsSignals is called to set signals before the
17169  truncate point, beginning with a red signal, and RemoveRouteElement called for all elements from the end to and including the truncate point.
17170 */
17171 {
17172  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTruncateElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
17173  "," + AnsiString((short)PrefDirRoute));
17174  bool ElementInRoute = false;
17175  bool TrainOccupyingRoute = false;
17176 
17177  for(unsigned int b = 0; b < PrefDirSize(); b++)
17178  {
17179  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc))
17180  {
17181  ElementInRoute = true;
17182  break;
17183  }
17184  }
17185  if(!ElementInRoute)
17186  {
17187  ReturnFlag = NotInRoute;
17188  Utilities->CallLogPop(336);
17189  return;
17190  }
17191 // it is in the route so continue, first look for a train or a flashing level crossing
17192  for(int b = PrefDirSize() - 1; b >= 0; b--)
17193  {
17194  int TrainID = Track->TrackElementAt(117, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnElement;
17195  if(PrefDirVector.at(b).TrackType == Bridge)
17196  {
17197  if(PrefDirVector.at(b).XLinkPos < 2)
17198  {
17199  TrainID = Track->TrackElementAt(118, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeTrackPos01;
17200  }
17201  else
17202  {
17203  TrainID = Track->TrackElementAt(119, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeTrackPos23;
17204  }
17205  }
17206  if(TrainID != -1)
17207  {
17208 // TrainController->StopTTClockMessage(56, "Can't truncate a route that is occupied by a train");
17209 // ReturnFlag = InRouteFalse;
17210 // Utilities->CallLogPop(337);
17211 // return;
17212 // above removed at v2.1.0 so that routes can be locked when occupied, below added
17213  TrainOccupyingRoute = true; // train is forward of the truncate point
17214  }
17215  if(Track->IsLCBarrierFlashingAtHV(3, PrefDirVector.at(b).HLoc, PrefDirVector.at(b).VLoc))
17216  {
17217  TrainController->StopTTClockMessage(79, "Can't cancel a route containing a level crossing that is changing state");
17218  ReturnFlag = InRouteFalse;
17219  Utilities->CallLogPop(1941);
17220  return;
17221  }
17222  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc))
17223  {
17224  break; // OK found truncate element & no flashing LC in front
17225  }
17226  }
17227 
17228  for(unsigned int b = 0; b < PrefDirSize(); b++)
17229  {
17230  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc)) // b = the truncate point
17231  {
17232  if(PrefDirVector.at(b).TrackType == Bridge)
17233  {
17234  TrainController->StopTTClockMessage(57, "Can't select a bridge as a route truncate point");
17235  ReturnFlag = InRouteFalse;
17236  Utilities->CallLogPop(338);
17237  return;
17238  }
17239  if(b == 1)
17240  {
17241  TrainController->StopTTClockMessage(58, "Can't truncate to a single route element");
17242  ReturnFlag = InRouteFalse;
17243  Utilities->CallLogPop(339);
17244  return;
17245  }
17246  if(b > 0)
17247  {
17248  TPrefDirElement TempElement = PrefDirVector.at(b - 1);
17249  if(TempElement.PrefDirRoute || TempElement.AutoSignals)
17250  {
17251  if(TempElement.Config[TempElement.XLinkPos] != Signal)
17252  {
17253  TrainController->StopTTClockMessage(59, "Must truncate to a valid signal - select position after signal");
17254  ReturnFlag = InRouteFalse;
17255  Utilities->CallLogPop(340);
17256  return;
17257  }
17258  }
17259  else
17260  {
17261  if((TempElement.TrackType == Points) || (TempElement.TrackType == Crossover) || (TempElement.TrackType == Bridge))
17262  {
17263  TrainController->StopTTClockMessage(60, "Can't truncate to points, bridge or crossover");
17264  ReturnFlag = InRouteFalse;
17265  Utilities->CallLogPop(341);
17266  return;
17267  }
17268  }
17269  }
17270  int RouteNumber;
17272 // Have to call RouteLockingRequired before SetAllRearwardsSignals because RouteLockingRequired tests the first rearward signal, if it is
17273 // red then locking is not required, and if call SetAllRearwardsSignals first then it will set the first rearward signal to red.
17274 
17275 // check if part of this route already locked & disallow if so
17276  if(!(AllRoutes->LockedRouteVector.empty()))
17277  {
17279  {
17280  if(LRVIT->RouteNumber == RouteNumber)
17281  {
17282  TrainController->StopTTClockMessage(61, "Can't truncate a route that is already part-locked");
17283  ReturnFlag = InRouteFalse;
17284  Utilities->CallLogPop(749);
17285  return;
17286  }
17287  }
17288  }
17289  if(AllRoutes->RouteLockingRequired(0, RouteNumber, b) || TrainOccupyingRoute) // added TrainOccupyingRoute at v2.1.0,
17290  // RouteLockingRequired only checks for trains approaching
17291  {
17294  int button = Application->MessageBox(L"Train approaching or occupying route, YES to lock route (2 minutes to release), NO to cancel",
17295  L"Warning!", MB_YESNO | MB_ICONWARNING);
17296  TrainController->BaseTime = TDateTime::CurrentDateTime();
17298  if(button == IDNO)
17299  {
17300  ReturnFlag = InRouteTrue; // still return true even though don't act on it
17301  Utilities->CallLogPop(342);
17302  return;
17303  }
17304  AnsiString LocID = AnsiString(Track->TrackElementAt(534, PrefDirVector.at(b).TrackVectorPosition).ElementID);
17305  TrainController->LogActionError(0, "", "", FailLockedRoute, LocID);
17306  TAllRoutes::TLockedRouteClass LockedRoute;
17307  bool ExistingLockedRouteModified = false;
17308  LockedRoute.RouteNumber = RouteNumber;
17309  LockedRoute.TruncateTrackVectorPosition = PrefDirVector.at(b).TrackVectorPosition;
17310  LockedRoute.LastTrackVectorPosition = PrefDirVector.at(PrefDirSize() - 1).TrackVectorPosition;
17311  LockedRoute.LastXLinkPos = PrefDirVector.at(PrefDirSize() - 1).XLinkPos;
17312  LockedRoute.LockStartTime = TrainController->TTClockTime;
17313 // but first check if this route already in LockedRouteVector (i.e. locked further along), and if so just change that vector entry
17314 // to use the new TruncateTrackVectorPosition & LockStartTime
17315  if(!AllRoutes->LockedRouteVector.empty())
17316  {
17317  for(TAllRoutes::TLockedRouteVectorIterator LRVIT = AllRoutes->LockedRouteVector.begin(); LRVIT < AllRoutes->LockedRouteVector.end();
17318  LRVIT++)
17319  {
17320  if(LRVIT->RouteNumber == RouteNumber)
17321  {
17322  LRVIT->TruncateTrackVectorPosition = LockedRoute.TruncateTrackVectorPosition;
17323  LRVIT->LockStartTime = LockedRoute.LockStartTime;
17324  ExistingLockedRouteModified = true;
17325  }
17326  }
17327  }
17328  if(!ExistingLockedRouteModified)
17329  {
17330  AllRoutes->LockedRouteVector.push_back(LockedRoute);
17331  }
17332  AllRoutes->SetAllRearwardsSignals(2, 0, RouteNumber, b);
17333  for(int c = PrefDirSize() - 1; c >= (int)b; c--) // must use int for >= test to succeed when b == 0
17334  {
17335  // return all signals to red in route section to be truncated
17336  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(61, RouteNumber).PrefDirVector.at(c);
17337  TTrackElement & TrackElement = Track->TrackElementAt(120, PrefDirElement.TrackVectorPosition);
17338  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
17339  {
17340  TrackElement.Attribute = 0;
17341  Track->PlotSignal(2, TrackElement, Display);
17342  Display->PlotOutput(18, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
17343  Display->PlotOutput(19, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
17344  }
17345  }
17346 // Display->Update();//not needed as Clearand... called on return from GetAllRoutesTruncateElement in InterfaceUnit
17347  ReturnFlag = InRouteTrue;
17348  }
17349  else
17350  {
17351  AllRoutes->SetAllRearwardsSignals(3, 0, RouteNumber, b);
17352  for(int c = PrefDirSize() - 1; c >= (int)b; c--) // must use int for >= test to succeed when b == 0
17353  {
17354  AllRoutes->RemoveRouteElement(5, LastElementPtr(3)->HLoc, LastElementPtr(4)->VLoc, LastElementPtr(5)->ELink);
17355  ReturnFlag = InRouteTrue;
17356  }
17357  }
17358  AllRoutes->CheckMapAndRoutes(5); // test
17359  Utilities->CallLogPop(343);
17360  return;
17361  }
17362  }
17363  ReturnFlag = NotInRoute;
17364  Utilities->CallLogPop(344);
17365 }
17366 
17367 // ---------------------------------------------------------------------------
17369 /*
17370  This is used when a train enters a route set in the opposite direction of travel (or at a crossover on a non-route line when the other
17371  track is in a route). The complete route is cancelled (but not linked routes), and all signals in the route are set to red.
17372  First all signals are set to red and replotted (without any route colours), then SetAllRearwardsSignals is called from the
17373  beginning of the route to set all linked rearwards route signals appropriately. Then all elements are removed from the route
17374  and RebuildRailwayFlag set (examined in Interface unit at each clock tick) to force a ClearandRebuildRailway to get rid of
17375  the route colours.
17376 */
17377 {
17378  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ForceCancelRoute");
17379  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
17381  int RouteNumber;
17382  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(4, GetFixedPrefDirElementAt(86, 0).TrackVectorPosition,
17383  GetFixedPrefDirElementAt(87, 0).XLinkPos, RouteNumber);
17384 
17385  if(RouteType != TAllRoutes::NoRoute) // it won't be, above only used to get RouteNumber for setting rearwards signals
17386  {
17387  for(unsigned int x = 0; x < PrefDirSize(); x++) // set all signals in route to red regardless of direction
17388  {
17389  if(PrefDirVector.at(x).TrackType == SignalPost)
17390  {
17391  Track->TrackElementAt(121, PrefDirVector.at(x).TrackVectorPosition).Attribute = 0; // red
17392  Track->PlotSignal(3, Track->TrackElementAt(122, PrefDirVector.at(x).TrackVectorPosition), Display);
17393  }
17394  }
17395  AllRoutes->SetAllRearwardsSignals(4, 0, RouteNumber, 0);
17396 // already set all signals to red in route so start at start of route for further rearwards signal setting
17397  }
17398  for(int c = PrefDirSize() - 1; c >= 0; c--) // must use int for >= test to succeed when b == 0
17399  {
17400  AllRoutes->RemoveRouteElement(6, LastElementPtr(6)->HLoc, LastElementPtr(7)->VLoc, LastElementPtr(8)->ELink);
17401  }
17402  AllRoutes->RebuildRailwayFlag = true; // set to force a ClearandRebuildRailway at next clock tick if not in zoom-out mode
17403  AllRoutes->CheckMapAndRoutes(9); // test
17404  TrainController->BaseTime = TDateTime::CurrentDateTime();
17406  Utilities->CallLogPop(345);
17407  return;
17408 }
17409 
17410 // ---------------------------------------------------------------------------
17411 
17412 void TOneRoute::SetRouteSearchVectorGraphics(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
17413 /*
17414  Set values for EXGraphicPtr and EntryDirectionGraphicPtr for all elements in SearchVector.
17415 */
17416 {
17417  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteSearchVectorGraphics," + AnsiString((short)AutoSigsFlag) + "," +
17418  AnsiString((short)PrefDirRoute));
17419  if(SearchVector.empty())
17420  {
17421  Utilities->CallLogPop(1149);
17422  return;
17423  }
17424  for(unsigned int b = 0; b < SearchVector.size(); b++)
17425  {
17428  PrefDirRoute);
17429  }
17430  Utilities->CallLogPop(346);
17431 }
17432 
17433 // ---------------------------------------------------------------------------
17434 
17435 void TOneRoute::SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
17436 /*
17437  Sets all element values in the RouteFlashVector (member of class TRouteFlash - defined in TOneRoute, of which
17438  TOneRoute has one member called RouteFlash) from the SearchVector. TRouteFlashElement is also a class defined in
17439  TOneRoute.
17440 */
17441 {
17442  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteAndLCChangeValues," + AnsiString((short)AutoSigsFlag) + "," +
17443  AnsiString((short)PrefDirRoute));
17444  RouteFlash.RouteFlashVector.clear();
17445  TRouteFlashElement RouteFlashElement;
17446 
17447  for(unsigned int b = 0; b < SearchVector.size(); b++)
17448  {
17449  int H = GetFixedSearchElementAt(11, b).HLoc;
17450  int V = GetFixedSearchElementAt(12, b).VLoc;
17452  RouteFlashElement.OverlayGraphic = GetModifiableSearchElementAt(6, b).GetRouteGraphicPtr(AutoSigsFlag, PrefDirRoute);
17453  RouteFlashElement.HLoc = H;
17454  RouteFlashElement.VLoc = V;
17456  RouteFlash.RouteFlashVector.push_back(RouteFlashElement);
17457  }
17458  Utilities->CallLogPop(348);
17459 }
17460 
17461 // ---------------------------------------------------------------------------
17462 
17463 void TOneRoute::SetLCChangeValues(int Caller, bool PrefDirRoute) //used when setting routes to start any included LC's lowering
17464 {
17465  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLCChangeValues," + AnsiString((short)PrefDirRoute));
17466  if(!PrefDirVector.empty())
17467  {
17468  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.end() - 1); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
17469  {
17470  int H = PrefDirPtr->HLoc;
17471  int V = PrefDirPtr->VLoc;
17472  // check for any LCs that are closed to trains & set the flash values and store in the vector
17473  if(Track->IsLCAtHV(39, H, V))
17474  {
17475  if(Track->IsLCBarrierUpAtHV(0, H, V))
17476  {
17477  Track->LCChangeFlag = true;
17478  TTrack::TActiveLevelCrossing CLC; // constructor sets ReducedTimePenalty to false
17479  CLC.HLoc = H;
17480  CLC.VLoc = V;
17482  CLC.BaseElementSpeedTag = PrefDirPtr->SpeedTag;
17485  if(PrefDirRoute)
17486  {
17487  CLC.TypeOfRoute = 1;
17488  }
17489  Track->SetLinkedLevelCrossingBarrierAttributes(1, H, V, 2); // set attr to 2 for changing state
17490  Track->ChangingLCVector.push_back(CLC);
17491  }
17492  }
17493  }
17494  }
17495  Utilities->CallLogPop(1948);
17496 }
17497 
17498 // ---------------------------------------------------------------------------
17499 
17501 /*
17502  Class TRouteFlash is defined in TOneRoute, which has one member called RouteFlash. This function
17503  checks first whether the OverlayPlotted flag is set and if not plots the OverlayGraphic for all
17504  elements in the RouteFlashVector, skipping any that a train is on. Finally the OverlayPlotted flag
17505  is set. The OverlayGraphic is set during TOneRoute::SetRouteAndLCChangeValues().
17506 */
17507 {
17508  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TRouteFlash::PlotRouteOverlay");
17509  if(!OverlayPlotted)
17510  {
17511  for(unsigned int x = 0; x < RouteFlashVector.size(); x++)
17512  {
17513  if(Track->TrackElementAt(123, RouteFlashVector.at(x).TrackVectorPosition).TrainIDOnElement > -1)
17514  {
17515  continue;
17516  }
17517  Display->PlotOutput(20, RouteFlashVector.at(x).HLoc * 16, RouteFlashVector.at(x).VLoc * 16, RouteFlashVector.at(x).OverlayGraphic);
17518  Display->Update();
17519  }
17520  OverlayPlotted = true;
17521  }
17522  Utilities->CallLogPop(349);
17523 }
17524 
17525 // ---------------------------------------------------------------------------
17526 
17528 /*
17529  Class TRouteFlash is defined in TOneRoute, which has one member called RouteFlash. This function
17530  checks first whether the OverlayPlotted flag is set and if so plots the OriginalGraphic for all
17531  elements in the RouteFlashVector, skipping any that a train is on. Finally the OverlayPlotted flag
17532  is reset. The OriginalGraphic is set during TOneRoute::SetRouteAndLCChangeValues().
17533 */
17534 {
17535  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TRouteFlash::PlotRouteOriginal");
17536  if(OverlayPlotted)
17537  {
17538  for(unsigned int x = 0; x < RouteFlashVector.size(); x++)
17539  {
17540  if(Track->TrackElementAt(124, RouteFlashVector.at(x).TrackVectorPosition).TrainIDOnElement > -1)
17541  {
17542  continue;
17543  }
17544  Display->PlotOutput(21, RouteFlashVector.at(x).HLoc * 16, RouteFlashVector.at(x).VLoc * 16, RouteFlashVector.at(x).OriginalGraphic);
17545  Display->Update();
17546  }
17547  OverlayPlotted = false;
17548  }
17549  Utilities->CallLogPop(350);
17550 }
17551 
17552 // ---------------------------------------------------------------------------
17553 
17554 const TOneRoute &TAllRoutes::GetFixedRouteAt(int Caller, int At) const
17555 {
17556  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedRouteAt," + AnsiString(At));
17557  if((At < 0) || ((unsigned int)At >= AllRoutesVector.size()))
17558  {
17559  throw Exception("Out of Range Error, vector size: " + AnsiString(AllRoutesVector.size()) + ", At: " + AnsiString(At) + " in GetFixedRouteAt");
17560  }
17561  Utilities->CallLogPop(120);
17562  return(AllRoutesVector.at(At));
17563 }
17564 
17565 // ---------------------------------------------------------------------------
17566 // ---------------------------------------------------------------------------
17567 
17569 {
17570  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableRouteAt," + AnsiString(At));
17571  if((At < 0) || ((unsigned int)At >= AllRoutesVector.size()))
17572  {
17573  throw Exception("Out of Range Error, vector size: " + AnsiString(AllRoutesVector.size()) + ", At: " + AnsiString(At) + " in GetModifiableRouteAt");
17574  }
17575  Utilities->CallLogPop(121);
17576  return(AllRoutesVector.at(At));
17577 }
17578 
17579 // ---------------------------------------------------------------------------
17580 
17581 void TAllRoutes::MarkAllRoutes(int Caller, TDisplay *Disp)
17582 /*
17583  Calls PrefDirMarker for all routes, with RouteCall set to identify a route call, and BuildingPrefDir false.
17584 */
17585 {
17586  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MarkAllRoutes");
17587  for(unsigned int a = 0; a < AllRoutesSize(); a++)
17588  {
17589  GetFixedRouteAt(62, a).PrefDirMarker(7, RouteCall, false, Disp);
17590  }
17591  Utilities->CallLogPop(351);
17592 }
17593 
17594 // ---------------------------------------------------------------------------
17595 
17596 void TAllRoutes::WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
17597 {
17598  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteAllRoutesToImage");
17599  for(unsigned int a = 0; a < AllRoutesSize(); a++)
17600  {
17601  GetFixedRouteAt(166, a).RouteImageMarker(0, Bitmap);
17602  }
17603  Utilities->CallLogPop(1706);
17604 }
17605 
17606 // ---------------------------------------------------------------------------
17607 
17608 bool TAllRoutes::GetAllRoutesTruncateElement(int Caller, int HLoc, int VLoc, bool PrefDirRoute)
17609 /*
17610  Examines all routes and for each uses GetRouteTruncateElement to see if the element at H & V is present in
17611  that route. The ReturnFlag value indicates InRouteTrue (success), InRouteFalse (failure), or NotInRoute.
17612  Messages are given in GetRouteTruncateElement. If successful the route is truncated at and including
17613  the element that matches H & V. If PrefDirRoute ensure only truncate to a signal, else prevent
17614  truncation to a crossover, bridge or points, also prevent route being left less than 2 elements in
17615  length (train length).
17616 */
17617 {
17618  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetAllRoutesTruncateElement," + AnsiString(HLoc) + "," +
17619  AnsiString(VLoc) + "," + AnsiString((short)PrefDirRoute));
17620  for(unsigned int a = 0; a < AllRoutesSize(); a++)
17621  {
17622  TTruncateReturnType ReturnFlag;
17623  RouteTruncateFlag = true;
17624 // used in SetRearwardsSignalsReturnFalseForTrain (called by GetRouteTruncateElement) to skip continuation & buffer attribute change
17625  GetModifiableRouteAt(7, a).GetRouteTruncateElement(0, HLoc, VLoc, PrefDirRoute, ReturnFlag);
17626  RouteTruncateFlag = false;
17627  if(ReturnFlag == NotInRoute)
17628  {
17629  continue;
17630  }
17631  else if(ReturnFlag == InRouteTrue)
17632  {
17633  Utilities->CallLogPop(352);
17634  return(true);
17635  }
17636  else if(ReturnFlag == InRouteFalse)
17637  {
17638  Utilities->CallLogPop(353);
17639  return(false);
17640  }
17641  }
17642  Utilities->CallLogPop(354);
17643  return(false);
17644 }
17645 
17646 // ---------------------------------------------------------------------------
17647 
17648 bool TAllRoutes::TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
17649 /*
17650  Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)
17651  is found it returns true (for crossovers & points returns true whichever track the route is on), else returns false.
17652 */
17653 {
17654  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackIsInARoute," + AnsiString(TrackVectorPosition) + "," +
17655  AnsiString(LinkPos));
17656  if(TrackVectorPosition == -1) // allows for continuation entries & exits
17657  {
17658  Utilities->CallLogPop(355);
17659  return(false);
17660  }
17661  THVPair Route2MultiMapKeyPair;
17662 
17663  Route2MultiMapKeyPair.first = Track->TrackElementAt(125, TrackVectorPosition).HLoc;
17664  Route2MultiMapKeyPair.second = Track->TrackElementAt(126, TrackVectorPosition).VLoc;
17665  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
17666  TRoute2MultiMapIterator Route2MultiMapIterator;
17667 
17668  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0) // none found
17669  {
17670  Utilities->CallLogPop(356);
17671  return(false);
17672  }
17673  if(Track->TrackElementAt(706, TrackVectorPosition).TrackType != Bridge) // if not a bridge doesn't matter which track the route is on
17674  {
17675  Utilities->CallLogPop(1422);
17676  return(true);
17677  }
17678  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
17679  {
17680  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
17681 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
17682 // realised after writing this that can't be points as would have been covered above, but leave anyway
17683  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(64, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(88,
17684  Route2MultiMapIterator->second.second);
17685  EntryLinkPos = PrefDirElement1.ELinkPos;
17686  ExitLinkPos = PrefDirElement1.XLinkPos;
17687  EntryLink = PrefDirElement1.Link[EntryLinkPos];
17688  ExitLink = PrefDirElement1.Link[ExitLinkPos];
17689  if(EntryLink == Track->TrackElementAt(127, TrackVectorPosition).Link[LinkPos])
17690  {
17691  Utilities->CallLogPop(357);
17692  return(true);
17693  }
17694  if(ExitLink == Track->TrackElementAt(128, TrackVectorPosition).Link[LinkPos])
17695  {
17696  Utilities->CallLogPop(358);
17697  return(true);
17698  }
17699  }
17700  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2) // if both tracks in route then must return true
17701  {
17702  Utilities->CallLogPop(1423);
17703  return(true);
17704  }
17705  Utilities->CallLogPop(363);
17706  return(false); // none found
17707 }
17708 
17709 // ---------------------------------------------------------------------------
17710 
17711 TAllRoutes::TRouteType TAllRoutes::GetRouteTypeAndGraphics(int Caller, int TrackVectorPosition, int LinkPos, Graphics::TBitmap* &EXGraphicPtr,
17712  Graphics::TBitmap* &EntryDirectionGraphicPtr)
17713 /*
17714  Examines Route2MultiMap and if finds the element at TrackVectorPosition with LinkPos (can be entry or exit) returns the appropriate route
17715  type - NoRoute, NotAutoSigsRoute, or AutoSigsRoute. If element not found then NoRoute is returned. If element is in a route then the EXGraphicPtr
17716  is returned, and if either the start or end of a route then the correct EntryDirectionGraphicPtr is returned, else a transparent element is returned.
17717  Function is used in TrainUnit for retaining AutoSigsRoutes but erasing others after train passes, and for picking up the correct background graphics
17718  for replotting of AutoSigsRoutes.
17719 */
17720 {
17721  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTypeAndGraphics," + AnsiString(TrackVectorPosition) + "," +
17722  AnsiString(LinkPos));
17723  EXGraphicPtr = RailGraphics->bmTransparentBgnd; // default value
17724  EntryDirectionGraphicPtr = RailGraphics->bmTransparentBgnd; // default value
17725  if(TrackVectorPosition == -1)
17726  {
17727  Utilities->CallLogPop(364);
17728  return(NoRoute); // allows for continuation entries & exits
17729  }
17730  THVPair Route2MultiMapKeyPair;
17731 
17732  Route2MultiMapKeyPair.first = Track->TrackElementAt(133, TrackVectorPosition).HLoc;
17733  Route2MultiMapKeyPair.second = Track->TrackElementAt(134, TrackVectorPosition).VLoc;
17734  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
17735  TRoute2MultiMapIterator Route2MultiMapIterator;
17736 
17737  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
17738  {
17739  Utilities->CallLogPop(365);
17740  return(NoRoute); // none found
17741  }
17742  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
17743  {
17744  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
17745 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
17746  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(73, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(97,
17747  Route2MultiMapIterator->second.second);
17748  EntryLinkPos = PrefDirElement1.ELinkPos;
17749  ExitLinkPos = PrefDirElement1.XLinkPos;
17750  EntryLink = PrefDirElement1.Link[EntryLinkPos];
17751  ExitLink = PrefDirElement1.Link[ExitLinkPos];
17752  if(EntryLink == Track->TrackElementAt(135, TrackVectorPosition).Link[LinkPos])
17753  {
17754  EXGraphicPtr = PrefDirElement1.EXGraphicPtr;
17755  if((Route2MultiMapIterator->second.second == 0) || (Route2MultiMapIterator->second.second == GetFixedRouteAt(74,
17756  Route2MultiMapIterator->second.first).PrefDirSize() - 1))
17757  {
17758  EntryDirectionGraphicPtr = PrefDirElement1.EntryDirectionGraphicPtr;
17759  }
17760  if(PrefDirElement1.AutoSignals)
17761  {
17762  Utilities->CallLogPop(366);
17763  return(AutoSigsRoute);
17764  }
17765  else
17766  {
17767  Utilities->CallLogPop(367);
17768  return(NotAutoSigsRoute);
17769  }
17770  }
17771  if(ExitLink == Track->TrackElementAt(136, TrackVectorPosition).Link[LinkPos])
17772  {
17773  EXGraphicPtr = PrefDirElement1.EXGraphicPtr;
17774  if((Route2MultiMapIterator->second.second == 0) || (Route2MultiMapIterator->second.second == GetFixedRouteAt(75,
17775  Route2MultiMapIterator->second.first).PrefDirSize() - 1))
17776  {
17777  EntryDirectionGraphicPtr = PrefDirElement1.EntryDirectionGraphicPtr;
17778  }
17779  if(PrefDirElement1.AutoSignals)
17780  {
17781  Utilities->CallLogPop(368);
17782  return(AutoSigsRoute);
17783  }
17784  else
17785  {
17786  Utilities->CallLogPop(369);
17787  return(NotAutoSigsRoute);
17788  }
17789  }
17790  }
17791  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
17792  {
17793  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
17794  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
17795 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
17796  const TPrefDirElement &PrefDirElement2 = GetFixedRouteAt(76, ItPair.first->second.first).GetFixedPrefDirElementAt(98, ItPair.first->second.second);
17797  EntryLinkPos = PrefDirElement2.ELinkPos;
17798  ExitLinkPos = PrefDirElement2.XLinkPos;
17799  EntryLink = PrefDirElement2.Link[EntryLinkPos];
17800  ExitLink = PrefDirElement2.Link[ExitLinkPos];
17801  if(EntryLink == Track->TrackElementAt(137, TrackVectorPosition).Link[LinkPos])
17802  {
17803  EXGraphicPtr = PrefDirElement2.EXGraphicPtr;
17804  if((ItPair.first->second.second == 0) || (ItPair.first->second.second == GetFixedRouteAt(77, ItPair.first->second.first).PrefDirSize() - 1))
17805  {
17806  EntryDirectionGraphicPtr = PrefDirElement2.EntryDirectionGraphicPtr;
17807  }
17808  if(PrefDirElement2.AutoSignals)
17809  {
17810  Utilities->CallLogPop(370);
17811  return(AutoSigsRoute);
17812  }
17813  else
17814  {
17815  Utilities->CallLogPop(371);
17816  return(NotAutoSigsRoute);
17817  }
17818  }
17819  if(ExitLink == Track->TrackElementAt(138, TrackVectorPosition).Link[LinkPos])
17820  {
17821  EXGraphicPtr = PrefDirElement2.EXGraphicPtr;
17822  if((ItPair.first->second.second == 0) || (ItPair.first->second.second == GetFixedRouteAt(78, ItPair.first->second.first).PrefDirSize() - 1))
17823  {
17824  EntryDirectionGraphicPtr = PrefDirElement2.EntryDirectionGraphicPtr;
17825  }
17826  if(PrefDirElement2.AutoSignals)
17827  {
17828  Utilities->CallLogPop(372);
17829  return(AutoSigsRoute);
17830  }
17831  else
17832  {
17833  Utilities->CallLogPop(373);
17834  return(NotAutoSigsRoute);
17835  }
17836  }
17837  ItPair.second--; // the second iterator points one past the last matching value
17838  const TPrefDirElement &PrefDirElement3 = GetFixedRouteAt(79, ItPair.second->second.first).GetFixedPrefDirElementAt(99, ItPair.second->second.second);
17839  EntryLinkPos = PrefDirElement3.ELinkPos;
17840  ExitLinkPos = PrefDirElement3.XLinkPos;
17841  EntryLink = PrefDirElement3.Link[EntryLinkPos];
17842  ExitLink = PrefDirElement3.Link[ExitLinkPos];
17843  if(EntryLink == Track->TrackElementAt(139, TrackVectorPosition).Link[LinkPos])
17844  {
17845  EXGraphicPtr = PrefDirElement3.EXGraphicPtr;
17846  if((ItPair.second->second.second == 0) || (ItPair.second->second.second == GetFixedRouteAt(80, ItPair.second->second.first).PrefDirSize() - 1))
17847  {
17848  EntryDirectionGraphicPtr = PrefDirElement3.EntryDirectionGraphicPtr;
17849  }
17850  if(PrefDirElement3.AutoSignals)
17851  {
17852  Utilities->CallLogPop(374);
17853  return(AutoSigsRoute);
17854  }
17855  else
17856  {
17857  Utilities->CallLogPop(375);
17858  return(NotAutoSigsRoute);
17859  }
17860  }
17861  if(ExitLink == Track->TrackElementAt(140, TrackVectorPosition).Link[LinkPos])
17862  {
17863  EXGraphicPtr = PrefDirElement3.EXGraphicPtr;
17864  if((ItPair.second->second.second == 0) || (ItPair.second->second.second == GetFixedRouteAt(81, ItPair.second->second.first).PrefDirSize() - 1))
17865  {
17866  EntryDirectionGraphicPtr = PrefDirElement3.EntryDirectionGraphicPtr;
17867  }
17868  if(PrefDirElement3.AutoSignals)
17869  {
17870  Utilities->CallLogPop(376);
17871  return(AutoSigsRoute);
17872  }
17873  else
17874  {
17875  Utilities->CallLogPop(377);
17876  return(NotAutoSigsRoute);
17877  }
17878  }
17879  }
17880  Utilities->CallLogPop(378);
17881  return(NoRoute); // none found
17882 }
17883 
17884 // ---------------------------------------------------------------------------
17885 TAllRoutes::TRouteType TAllRoutes::GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
17886 /*
17887  Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit) is found returns the appropriate
17888  route type - NoRoute, NotAutoSigsRoute, or AutoSigsRoute and number.
17889 */
17890 {
17891  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTypeAndNumber," + AnsiString(TrackVectorPosition) + "," +
17892  AnsiString(LinkPos));
17893  if(TrackVectorPosition == -1)
17894  {
17895  RouteNumber = -1;
17896  Utilities->CallLogPop(379);
17897  return(NoRoute); // allows for continuation & buffer entries & exits
17898  }
17899  THVPair Route2MultiMapKeyPair;
17900 
17901  Route2MultiMapKeyPair.first = Track->TrackElementAt(141, TrackVectorPosition).HLoc;
17902  Route2MultiMapKeyPair.second = Track->TrackElementAt(142, TrackVectorPosition).VLoc;
17903  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
17904  TRoute2MultiMapIterator Route2MultiMapIterator;
17905 
17906  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
17907  {
17908  RouteNumber = -1;
17909  Utilities->CallLogPop(380);
17910  return(NoRoute); // none found
17911  }
17912  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
17913  {
17914  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
17915 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
17916  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(82, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(100,
17917  Route2MultiMapIterator->second.second);
17918  EntryLinkPos = PrefDirElement1.ELinkPos;
17919  ExitLinkPos = PrefDirElement1.XLinkPos;
17920  EntryLink = PrefDirElement1.Link[EntryLinkPos];
17921  ExitLink = PrefDirElement1.Link[ExitLinkPos];
17922  if(EntryLink == Track->TrackElementAt(143, TrackVectorPosition).Link[LinkPos])
17923  {
17924  RouteNumber = Route2MultiMapIterator->second.first;
17925  if(PrefDirElement1.AutoSignals)
17926  {
17927  Utilities->CallLogPop(381);
17928  return(AutoSigsRoute);
17929  }
17930  else
17931  {
17932  Utilities->CallLogPop(382);
17933  return(NotAutoSigsRoute);
17934  }
17935  }
17936  if(ExitLink == Track->TrackElementAt(144, TrackVectorPosition).Link[LinkPos])
17937  {
17938  RouteNumber = Route2MultiMapIterator->second.first;
17939  if(PrefDirElement1.AutoSignals)
17940  {
17941  Utilities->CallLogPop(383);
17942  return(AutoSigsRoute);
17943  }
17944  else
17945  {
17946  Utilities->CallLogPop(384);
17947  return(NotAutoSigsRoute);
17948  }
17949  }
17950  }
17951  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
17952  {
17953  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
17954  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
17955 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
17956  const TPrefDirElement &PrefDirElement2 = GetFixedRouteAt(83, ItPair.first->second.first).GetFixedPrefDirElementAt(101, ItPair.first->second.second);
17957  EntryLinkPos = PrefDirElement2.ELinkPos;
17958  ExitLinkPos = PrefDirElement2.XLinkPos;
17959  EntryLink = PrefDirElement2.Link[EntryLinkPos];
17960  ExitLink = PrefDirElement2.Link[ExitLinkPos];
17961  if(EntryLink == Track->TrackElementAt(145, TrackVectorPosition).Link[LinkPos])
17962  {
17963  RouteNumber = ItPair.first->second.first;
17964  if(PrefDirElement2.AutoSignals)
17965  {
17966  Utilities->CallLogPop(385);
17967  return(AutoSigsRoute);
17968  }
17969  else
17970  {
17971  Utilities->CallLogPop(386);
17972  return(NotAutoSigsRoute);
17973  }
17974  }
17975  if(ExitLink == Track->TrackElementAt(146, TrackVectorPosition).Link[LinkPos])
17976  {
17977  RouteNumber = ItPair.first->second.first;
17978  if(PrefDirElement2.AutoSignals)
17979  {
17980  Utilities->CallLogPop(387);
17981  return(AutoSigsRoute);
17982  }
17983  else
17984  {
17985  Utilities->CallLogPop(388);
17986  return(NotAutoSigsRoute);
17987  }
17988  }
17989  ItPair.second--; // the second iterator points one past the last matching value
17990  const TPrefDirElement &PrefDirElement3 = GetFixedRouteAt(84, ItPair.second->second.first).GetFixedPrefDirElementAt(102, ItPair.second->second.second);
17991  EntryLinkPos = PrefDirElement3.ELinkPos;
17992  ExitLinkPos = PrefDirElement3.XLinkPos;
17993  EntryLink = PrefDirElement3.Link[EntryLinkPos];
17994  ExitLink = PrefDirElement3.Link[ExitLinkPos];
17995  if(EntryLink == Track->TrackElementAt(147, TrackVectorPosition).Link[LinkPos])
17996  {
17997  RouteNumber = ItPair.second->second.first;
17998  if(PrefDirElement3.AutoSignals)
17999  {
18000  Utilities->CallLogPop(389);
18001  return(AutoSigsRoute);
18002  }
18003  else
18004  {
18005  Utilities->CallLogPop(390);
18006  return(NotAutoSigsRoute);
18007  }
18008  }
18009  if(ExitLink == Track->TrackElementAt(148, TrackVectorPosition).Link[LinkPos])
18010  {
18011  RouteNumber = ItPair.second->second.first;
18012  if(PrefDirElement3.AutoSignals)
18013  {
18014  Utilities->CallLogPop(391);
18015  return(AutoSigsRoute);
18016  }
18017  else
18018  {
18019  Utilities->CallLogPop(392);
18020  return(NotAutoSigsRoute);
18021  }
18022  }
18023  }
18024  RouteNumber = -1;
18025  Utilities->CallLogPop(393);
18026  return(NoRoute); // none found
18027 }
18028 
18029 // ---------------------------------------------------------------------------
18030 
18031 void TAllRoutes::StoreOneRoute(int Caller, TOneRoute *Route)
18032 /*
18033  A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector, which, since it is the last to be added, will have
18034  a RouteNumber of AllRoutesSize() - 1. Then each element of the new route is added in turn using AddRouteElement,
18035  which uses HLoc, VLoc, ELink and RouteNumber to provide the information necessary to insert it into both PrefDirVector
18036  and Route2MultiMap.
18037 */
18038 {
18039  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StoreOneRoute");
18040  TOneRoute EmptyRoute;
18041 
18042  EmptyRoute.RouteID = NextRouteID;
18043  NextRouteID++;
18044 
18045  AllRoutesVector.push_back(EmptyRoute); // to create a new route vector entry
18046  for(unsigned int x = 0; x < Route->PrefDirSize(); x++)
18047  {
18048  AddRouteElement(0, Route->GetFixedPrefDirElementAt(127, x).HLoc, Route->GetFixedPrefDirElementAt(128, x).VLoc,
18049  Route->GetFixedPrefDirElementAt(129, x).GetELink(), AllRoutesSize() - 1, Route->GetFixedPrefDirElementAt(130, x));
18050  }
18051  int FirstVecPos = Route->GetFixedPrefDirElementAt(199, 0).TrackVectorPosition;
18052  int LastVecPos = Route->GetFixedPrefDirElementAt(200, (Route->PrefDirSize()) - 1).TrackVectorPosition;
18053 
18054  TrainController->LogEvent("StoreOneRoute," + AnsiString(EmptyRoute.RouteID) + "," + AnsiString(FirstVecPos) + "," + AnsiString(LastVecPos));
18055  Utilities->CallLogPop(394);
18056 }
18057 
18058 // ---------------------------------------------------------------------------
18059 
18061 /*
18062  A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector after a session load. For this the RouteID
18063  that is already in Route is used.
18064 */
18065 {
18066  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StoreOneRouteAfterSessionLoad");
18067  TOneRoute EmptyRoute;
18068 
18069  EmptyRoute.RouteID = Route->RouteID;
18070 
18071  AllRoutesVector.push_back(EmptyRoute); // to create a new route vector entry
18072  for(unsigned int x = 0; x < Route->PrefDirSize(); x++)
18073  {
18074  AddRouteElement(3, Route->GetFixedPrefDirElementAt(189, x).HLoc, Route->GetFixedPrefDirElementAt(190, x).VLoc,
18075  Route->GetFixedPrefDirElementAt(191, x).GetELink(), AllRoutesSize() - 1, Route->GetFixedPrefDirElementAt(192, x));
18076  }
18077  Utilities->CallLogPop(1579);
18078 }
18079 
18080 // ---------------------------------------------------------------------------
18081 
18082 void TAllRoutes::ClearRouteDuringRouteBuildingAt(int Caller, int RouteNumber)
18083 /*
18084  When attaching a new route section to an existing route, it is sometimes necessary to erase the
18085  original route and create a new composite route. This function Erases all elements in the route
18086  at RouteNumber using TAllRoutes->RemoveRouteElement to clear elements from Route2MultiMap and
18087  from the PrefDirVector. Since all elements for the route are removed RemoveRouteElement also
18088  clears the Route from AllRoutesVector. Route numbers are decremented in the map for route numbers
18089  that are greater than the route number that is removed. The LockedRouteVector as also searched
18090  and if any relate to the route that has been cleared they are erased too, but the fact that one
18091  has been found is recorded so that it can be re-established later.
18092 */
18093 {
18094  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ClearRouteDuringRouteBuildingAt," + AnsiString(RouteNumber));
18095  THVPair Route2MultiMapKeyPair;
18096  TRoute2MultiMapEntry Route2MultiMapEntry;
18097  TRoute2MultiMapIterator Route2MultiMapIterator;
18098 
18099 // need to check LockedVector first, and erase it if it's the route to be cleared, and to reinstate it as a new locked route with the same
18100 // values (except RouteNumber) when the new route is established (in ConvertAndAdd...).
18101 // If clear all route elements first then when the last is cleared the LockedVector.RouteNumber values are decremented if they are higher
18102 // then the cleared route number (by RemoveRouteElement), and one of the new values may be the same number as the old cleared route number.
18103 // If so the locked route is removed from the locked vector and is lost.
18104  LockedRouteTruncateTrackVectorPosition = 0;
18105  LockedRouteLastTrackVectorPosition = 0;
18106  LockedRouteLastXLinkPos = 0;
18107  LockedRouteLockStartTime = TDateTime(0);
18108  if(!LockedRouteVector.empty())
18109  {
18110  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
18111  {
18112  if(LRVIT->RouteNumber == RouteNumber)
18113  {
18114  LockedRouteTruncateTrackVectorPosition = LRVIT->TruncateTrackVectorPosition;
18115  LockedRouteLastTrackVectorPosition = LRVIT->LastTrackVectorPosition;
18116  LockedRouteLastXLinkPos = LRVIT->LastXLinkPos;
18117  LockedRouteLockStartTime = LRVIT->LockStartTime;
18118  LockedRouteFoundDuringRouteBuilding = true;
18119  LockedRouteVector.erase(LRVIT);
18120  }
18121  }
18122  }
18123  for(int x = (AllRoutes->GetFixedRouteAt(109, RouteNumber).PrefDirSize()) - 1; x >= 0; x--)
18124  {
18125  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(110, RouteNumber).GetFixedPrefDirElementAt(131, x);
18126  AllRoutes->RemoveRouteElement(7, PrefDirElement.HLoc, PrefDirElement.VLoc, PrefDirElement.GetELink());
18127  }
18128  Utilities->CallLogPop(395);
18129 }
18130 
18131 // ---------------------------------------------------------------------------
18132 
18134  TRoute2MultiMapIterator &Route2MultiMapIterator)
18135 /*
18136  Examines Route2MultiMap and returns a TRouteElementPair if one is found with the passed values of H, V and ELink.
18137  Also returned as a reference is an iterator to the found element in the map to assist in erasing it. Called by
18138  TAllRoutes::RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink). Note that only need ELink (as well as H & V) to
18139  identify uniquely, since only bridges can have two routes on them & their track ELinks are always different. Messages
18140  are given for failure.
18141 */
18142 {
18143  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindRoutePairFromRoute2MultiMap," + AnsiString(HLoc) + "," +
18144  AnsiString(VLoc) + "," + AnsiString(ELink));
18145  TRouteElementPair ReturnPair;
18146 
18147  ReturnPair.first = -1;
18148  ReturnPair.second = 0;
18149  THVPair Route2MultiMapKeyPair;
18150 
18151  Route2MultiMapKeyPair.first = HLoc;
18152  Route2MultiMapKeyPair.second = VLoc;
18153  TRoute2MultiMapEntry Route2MultiMapEntry;
18154 
18155  Route2MultiMapEntry.first = Route2MultiMapKeyPair;
18156  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
18157 
18158  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
18159  Route2MultiMapIterator = ItPair.first;
18160 
18161  if(ItPair.first == ItPair.second)
18162  {
18163  throw Exception("Failed to find Route2MultiMap element at HLoc = " + (AnsiString)HLoc + " VLoc = " + (AnsiString)VLoc);
18164  }
18165  if(GetFixedRouteAt(111, ItPair.first->second.first).GetFixedPrefDirElementAt(132, ItPair.first->second.second).GetELink() == ELink)
18166  {
18167  ReturnPair.first = ItPair.first->second.first;
18168  ReturnPair.second = ItPair.first->second.second;
18169  Route2MultiMapIterator = ItPair.first;
18170  Utilities->CallLogPop(396);
18171  return(ReturnPair);
18172  }
18173  ItPair.first++;
18174  if(ItPair.first == ItPair.second)
18175  {
18176  throw Exception("Found Route2MultiMap element at HLoc = " + (AnsiString)HLoc + " VLoc = " + (AnsiString)VLoc + " but failed to find required element");
18177  }
18178  if(GetFixedRouteAt(112, ItPair.first->second.first).GetFixedPrefDirElementAt(133, ItPair.first->second.second).GetELink() == ELink)
18179  {
18180  ReturnPair.first = ItPair.first->second.first;
18181  ReturnPair.second = ItPair.first->second.second;
18182  Route2MultiMapIterator = ItPair.first;
18183  Utilities->CallLogPop(397);
18184  return(ReturnPair);
18185  }
18186  Utilities->CallLogPop(398);
18187  return(ReturnPair);
18188 }
18189 
18190 // ---------------------------------------------------------------------------
18191 
18192 bool TAllRoutes::FindRouteNumberFromRoute2MultiMapNoErrors(int Caller, int HLoc, int VLoc, int ELink, int &RouteNumber) // new at v1.2.0
18193 /*
18194  Similar to above but returns a bool and no errors are reported for no route or element at H&V etc.
18195  Examines Route2MultiMap and returns true if a route is found with the passed values of H, V and ELink.
18196  RouteNumber (route position in AllRoutes vector is returned as a reference.
18197  Called by TTrain::CheckAndCancelRouteForWrongEndEntry. Note that only need ELink (as well as H & V) to
18198  identify uniquely, since only bridges can have two routes on them & their track ELinks are always different.
18199 */
18200 {
18201  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindRouteNumberFromRoute2MultiMapNoErrors," + AnsiString(HLoc) + "," +
18202  AnsiString(VLoc) + "," + AnsiString(ELink));
18203  THVPair Route2MultiMapKeyPair;
18204 
18205  Route2MultiMapKeyPair.first = HLoc;
18206  Route2MultiMapKeyPair.second = VLoc;
18207  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
18208 
18209  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
18210 
18211  if(ItPair.first == ItPair.second)
18212  {
18213  RouteNumber = -1;
18214  Utilities->CallLogPop(2032);
18215  return(false);
18216  }
18217  if(GetFixedRouteAt(205, ItPair.first->second.first).GetFixedPrefDirElementAt(241, ItPair.first->second.second).GetELink() == ELink)
18218  {
18219  RouteNumber = ItPair.first->second.first;
18220  Utilities->CallLogPop(2033);
18221  return(true);
18222  }
18223  ItPair.first++;
18224 
18225  if(ItPair.first == ItPair.second)
18226  {
18227  RouteNumber = -1;
18228  Utilities->CallLogPop(2034);
18229  return(false);
18230  }
18231  if(GetFixedRouteAt(206, ItPair.first->second.first).GetFixedPrefDirElementAt(242, ItPair.first->second.second).GetELink() == ELink)
18232  {
18233  RouteNumber = ItPair.first->second.first;
18234  Utilities->CallLogPop(2035);
18235  return(true);
18236  }
18237  RouteNumber = -1;
18238  Utilities->CallLogPop(2036);
18239  return(false);
18240 }
18241 
18242 // ---------------------------------------------------------------------------
18243 
18244 void TAllRoutes::Route2MultiMapInsert(int Caller, int HLoc, int VLoc, int ELinkIn, int RouteNumber, unsigned int RouteElementNumber)
18245 /*
18246  Elink needed in case it's a bridge, & need to know whether the found element is on this route or not. First check if an
18247  entry in the map already exists at H & V, and if so check that it's a bridge with existing route on other track.
18248  That being so insert the new element. If it's not a bridge, or the route has the same ELink value as the element to
18249  be inserted, give appropriate messages. If there isn't an element at H & V already in the map insert it.
18250  Called by TAllRoutes::AddRouteElement.
18251 */
18252 {
18253  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",Route2MultiMapInsert," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
18254  "," + AnsiString(ELinkIn) + "," + AnsiString(RouteNumber) + "," + AnsiString(RouteElementNumber));
18255  THVPair Route2MultiMapKeyPair;
18256 
18257  Route2MultiMapKeyPair.first = HLoc;
18258  Route2MultiMapKeyPair.second = VLoc;
18259  TRoute2MultiMapEntry Route2MultiMapEntry;
18260 
18261  Route2MultiMapEntry.first = Route2MultiMapKeyPair;
18262  TRouteElementPair RouteElementPair;
18263 
18264  RouteElementPair.first = RouteNumber;
18265  RouteElementPair.second = RouteElementNumber;
18266  Route2MultiMapEntry.second = RouteElementPair;
18267 
18268  if(Route2MultiMap.find(Route2MultiMapKeyPair) != Route2MultiMap.end())
18269  // true for element at H&V already included in map, has to be a bridge with existing route on opposite track to be valid
18270  {
18271  if(GetFixedRouteAt(113, Route2MultiMap.find(Route2MultiMapKeyPair)->second.first).GetFixedPrefDirElementAt(134,
18272  Route2MultiMap.find(Route2MultiMapKeyPair)->second.second).GetELink() != ELinkIn)
18273  // element already at H&V has different ELink to element to be inserted, so must be a bridge with existing route on opposite treack
18274  {
18275  if(GetFixedRouteAt(114, Route2MultiMap.find(Route2MultiMapKeyPair)->second.first).GetFixedPrefDirElementAt(135,
18276  Route2MultiMap.find(Route2MultiMapKeyPair)->second.second).TrackType != Bridge)
18277  {
18278  throw Exception("Error, bridge expected in Route2MultiMapInsert but not, at HLoc=" + AnsiString(HLoc) + " VLoc=" + AnsiString(VLoc));
18279  }
18280  Route2MultiMap.insert(Route2MultiMapEntry); // insert bridge into map again but now with the new track as part of required route
18281  }
18282  else
18283  // same ELink so have an error
18284  {
18285  throw Exception("Error, route map entry found in Route2MultiMapInsert at HLoc=" + AnsiString(HLoc) + " VLoc=" + AnsiString(VLoc));
18286  }
18287  }
18288  else
18289  {
18290  Route2MultiMap.insert(Route2MultiMapEntry);
18291  }
18292 // element at H&V not found in map so insert it
18293  Utilities->CallLogPop(399);
18294 }
18295 
18296 // ---------------------------------------------------------------------------
18297 
18299 /*
18300  Retrieve up to two TRouteElementPair entries from Route2MultiMap at H & V, the first as a function return
18301  and the second in the reference SecondPair. If there's only one then it's the function return
18302 */
18303 {
18304  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteElementDataFromRoute2MultiMap," + AnsiString(HLoc) + "," +
18305  AnsiString(VLoc));
18307 
18308  TempPair.first = -1;
18309  TempPair.second = 0;
18310  SecondPair = TempPair;
18311  TRoute2MultiMapIterator Route2MultiMapIterator;
18312  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItRange;
18313  THVPair Route2MultiMapKeyPair;
18314 
18315  Route2MultiMapKeyPair.first = HLoc;
18316  Route2MultiMapKeyPair.second = VLoc;
18317  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
18318  {
18319  Utilities->CallLogPop(400);
18320  return(TempPair);
18321  }
18322  else if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
18323  {
18324  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
18325  Utilities->CallLogPop(401);
18326  return(Route2MultiMapIterator->second);
18327  }
18328  else if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
18329  {
18330  ItRange = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
18331  TempPair = ItRange.first->second;
18332  SecondPair = (--ItRange.second)->second; // 2nd iterator points past the last value
18333  Utilities->CallLogPop(402);
18334  return(TempPair);
18335  }
18336  Utilities->CallLogPop(403);
18337  return(TempPair);
18338 }
18339 
18340 // ---------------------------------------------------------------------------
18341 
18342 void TAllRoutes::CheckMapAndRoutes(int Caller) // test
18343 /*
18344  Checks equivalence for each route between entries in PrefDirVector and those in Route2MultiMap, and also that the size
18345  of the multimap and the sum of the sizes of all PrefDirVectors is the same.
18346 */
18347 {
18348  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndRoutes");
18349  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
18350  {
18351  for(unsigned int b = 0; b < AllRoutes->GetFixedRouteAt(115, a).PrefDirSize(); b++)
18352  {
18353  TPrefDirElement CheckElement = AllRoutes->GetFixedRouteAt(116, a).GetFixedPrefDirElementAt(136, b);
18354  TAllRoutes::TRouteElementPair SecondPair;
18355  TRouteElementPair RouteElementPair = GetRouteElementDataFromRoute2MultiMap(8, CheckElement.HLoc, CheckElement.VLoc, SecondPair);
18356  if(RouteElementPair.first == -1)
18357  // failed to find element in multimap
18358  {
18359  throw Exception("CheckMapAndRoutes Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
18360  " in Route2MultiMap, Caller=" + (AnsiString)Caller);
18361  }
18362  if((RouteElementPair.first != (int)a) && (SecondPair.first != (int)a))
18363  // neither pair has expected route number
18364  {
18365  throw Exception("CheckMapAndRoutes Error - RouteNumber failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
18366  (AnsiString)CheckElement.VLoc + " Map value=" + (AnsiString)RouteElementPair.first + " Route value=" + (AnsiString)a + " Caller=" +
18367  (AnsiString)Caller);
18368  }
18369  if(((RouteElementPair.first != (int)a) || (RouteElementPair.second != b)) && ((SecondPair.first != (int)a) || (SecondPair.second != b)))
18370  // need one of pairs to match both RouteNumber and RouteElementNumber or fails
18371  {
18372  throw Exception("CheckMapAndRoutes Error - PrefDirVectorNumber failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
18373  (AnsiString)CheckElement.VLoc + " 1st Map value RouteNum/ElementNum =" + (AnsiString)RouteElementPair.first + "/" +
18374  (AnsiString)RouteElementPair.second + " 2nd Map value =" + (AnsiString)SecondPair.first + "/" + (AnsiString)SecondPair.second +
18375  " Route value=" + (AnsiString)a + "/" + (AnsiString)b + " Caller=" + (AnsiString)Caller);
18376  }
18377  }
18378  }
18379  unsigned int SizeVal = 0;
18380 
18381 // check map and sum of route sizes match
18382  for(unsigned int a = 0; a < AllRoutesSize(); a++)
18383  {
18384  SizeVal += GetFixedRouteAt(117, a).PrefDirSize();
18385  }
18386  if(SizeVal != Route2MultiMap.size())
18387  {
18388  throw Exception("CheckMapAndRoutes Error - Map Size=" + (AnsiString)Route2MultiMap.size() + " RouteSize=" + (AnsiString)SizeVal + " Caller=" +
18389  (AnsiString)Caller);
18390  }
18391  Utilities->CallLogPop(404);
18392  return;
18393 }
18394 
18395 // ---------------------------------------------------------------------------
18396 
18397 void TAllRoutes::DecrementRouteNumbersInRoute2MultiMap(int Caller, int RouteNumber)
18398 /*
18399  After a route has been erased from AllRoutesVector and its entries from Route2MultiMap, this
18400  function examines all the remaining entries in Route2MultiMap to see if their RouteNumbers
18401  exceed that for the erased route. Where this is so the RouteNumber is decremented.
18402 */
18403 {
18404  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementRouteNumbersInRoute2MultiMap," + AnsiString(RouteNumber));
18405  if(!Route2MultiMap.empty())
18406  {
18407  for(TRoute2MultiMapIterator Route2MultiMapIterator = Route2MultiMap.begin(); Route2MultiMapIterator != Route2MultiMap.end(); Route2MultiMapIterator++)
18408  {
18409  if(Route2MultiMapIterator->second.first > RouteNumber)
18410  {
18411  Route2MultiMapIterator->second.first--;
18412  }
18413  }
18414  }
18415  Utilities->CallLogPop(405);
18416 }
18417 
18418 // ---------------------------------------------------------------------------
18419 
18420 void TAllRoutes::DecrementRouteElementNumbersInRoute2MultiMap(int Caller, int RouteNumber, unsigned int ErasedElementNumber)
18421 /*
18422  After a route element has been erased from the relevant PrefDirVector and from Route2MultiMap, this
18423  function examines all the remaining entries in Route2MultiMap with the same RouteNumber as that
18424  for the erased element. Where a RouteElementNumber exceeds that for the erased element it is decremented.
18425 */
18426 {
18427  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementRouteElementNumbersInRoute2MultiMap," +
18428  AnsiString(RouteNumber) + "," + AnsiString(ErasedElementNumber));
18429  if(!Route2MultiMap.empty())
18430  {
18431  for(TRoute2MultiMapIterator Route2MultiMapIterator = Route2MultiMap.begin(); Route2MultiMapIterator != Route2MultiMap.end(); Route2MultiMapIterator++)
18432  {
18433  if((Route2MultiMapIterator->second.first == RouteNumber) && (Route2MultiMapIterator->second.second > ErasedElementNumber))
18434  {
18435  Route2MultiMapIterator->second.second--;
18436  }
18437  }
18438  }
18439  Utilities->CallLogPop(406);
18440 }
18441 
18442 // ---------------------------------------------------------------------------
18443 
18444 void TAllRoutes::RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
18445 /*
18446  Erases the route element from Route2MultiMap and from the PrefDirVector.
18447  If there are no elements left in the PrefDirVector the route is cleared from AllRoutesVector. Route element numbers in the map are
18448  decremented if they are greater than the element number removed, and if the entire route is removed
18449  then the route numbers are also decremented in the map for route numbers that are greater than the route
18450  number that is removed.
18451 */
18452 {
18453  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RemoveRouteElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
18454  AnsiString(ELink));
18455  TRouteElementPair RequiredRoutePair; // RouteNumber & RouteElementNumber
18456  TRoute2MultiMapIterator Route2MultiMapIterator;
18457 
18458  RequiredRoutePair = FindRoutePairFromRoute2MultiMap(0, HLoc, VLoc, ELink, Route2MultiMapIterator);
18459  if(RequiredRoutePair.first == -1)
18460  {
18461  throw Exception("Failed to find route element in RemoveRouteElement");
18462  }
18463  Route2MultiMap.erase(Route2MultiMapIterator);
18464  DecrementRouteElementNumbersInRoute2MultiMap(0, RequiredRoutePair.first, RequiredRoutePair.second);
18465 
18466 // even though element has been erased from the routemap, RequiredRoutePair still contains the element values
18467  TPrefDirElement LockedRouteElement, PrefDirElement = GetFixedRouteAt(118, RequiredRoutePair.first).GetFixedPrefDirElementAt(137, RequiredRoutePair.second);
18468 
18469  if(Track->TrackElementAt(157, PrefDirElement.TrackVectorPosition).Config[PrefDirElement.XLinkPos] == Signal)
18470  {
18471  Track->TrackElementAt(158, PrefDirElement.TrackVectorPosition).Attribute = 0; // change forward signals back to red
18472  }
18473 // don't need the section below (a) because when a train removes elements from the front of a locked route, there is a test in
18474 // ApproachLocking to determine whether the element immediately nearer the start of the route to the element being removed is still
18475 // present, and of not the element removal stops; and (b) because it never worked anyway! - IsElementInLockedRoute.... uses Route2MultiMap
18476 // to check if a route element is present, and the element has already been removed from the map - see above.
18477 
18478 // before erase the element check if it's in a locked route, and if so change the TruncateTrackVectorPosition to the next valid (XLinkPos] element position
18479 /*
18480  int LockedVectorNumber = -1;
18481  if(IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(5, PrefDirElement.TrackVectorPosition, PrefDirElement.XLinkPos, LockedRouteElement, LockedVectorNumber))
18482  {
18483  LockedRouteVector.at(LockedVectorNumber).TruncateTrackVectorPosition = PrefDirElement.Conn[PrefDirElement.XLinkPos];
18484  }
18485 */
18486 
18487 // erase element from route
18488  GetModifiableRouteAt(8, RequiredRoutePair.first).EraseRouteElementAt(&(GetModifiableRouteAt(9, RequiredRoutePair.first).GetModifiablePrefDirElementAt(1,
18489  RequiredRoutePair.second)));
18490 // CheckMapAndRoutes();//test - drop - tested below
18491 
18492 // remove ContinuationAutoSig route if element is in one since if any part of it is truncated the continuation exit will be removed - must
18493 // be so as continuation exit is at the end of the route, and truncation is from the end
18495  {
18497  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
18498  AutoSigVectorIT--)
18499  {
18500  if(AutoSigVectorIT->RouteNumber == RequiredRoutePair.first)
18501  {
18502  TrainController->ContinuationAutoSigVector.erase(AutoSigVectorIT);
18503  }
18504  }
18505  }
18506 // now if last element from a route was removed need to remove the route from the route vector and from the LockedRouteVector if exists,
18507 // and adjust all the corresponding route numbers
18508  if(GetModifiableRouteAt(10, RequiredRoutePair.first).PrefDirSize() == 0)
18509  {
18510  TrainController->LogEvent("RouteRemoved," + AnsiString(GetFixedRouteAt(189, RequiredRoutePair.first).RouteID));
18511  AllRoutesVector.erase(AllRoutesVector.begin() + RequiredRoutePair.first);
18512  DecrementRouteNumbersInRoute2MultiMap(0, RequiredRoutePair.first);
18513 
18514 /* drop this: LockedVectorNumber was supposed to be determined from the above section that has been dropped, so this doesn't work
18515  It isn't needed anyway as a check is made after the Locked route timeout as to whether the end element is in a route or not, and if not
18516  it is erased then - see TInterface::ApproachLocking
18517 
18518  if(LockedVectorNumber > -1)
18519  {
18520  LockedRouteVector.erase(LockedRouteVector.begin() + LockedVectorNumber);
18521  }
18522 */
18523  // decrement route numbers in the locked route vector whether or not this route is a locked route
18524  if(!LockedRouteVector.empty())
18525  {
18526  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
18527  {
18528  if(LRVIT->RouteNumber > RequiredRoutePair.first)
18529  {
18530  LRVIT->RouteNumber--;
18531  }
18532  }
18533  }
18535  {
18537  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
18538  AutoSigVectorIT--)
18539  {
18540  if(AutoSigVectorIT->RouteNumber > RequiredRoutePair.first)
18541  {
18542  AutoSigVectorIT->RouteNumber--;
18543  }
18544  }
18545  }
18546  }
18547  CheckMapAndRoutes(7); // test
18548  Utilities->CallLogPop(407);
18549 }
18550 
18551 // ---------------------------------------------------------------------------
18552 
18553 void TAllRoutes::AddRouteElement(int Caller, int HLoc, int VLoc, int ELink, int RouteNumber, TPrefDirElement RouteElement)
18554 /*
18555  A single TPrefDirElement is added to both PrefDirVector (for the route at RouteNumber) and Route2MultiMap.
18556  Called from TAllRoutes::StoreOneRoute. Note that the IsARoute boolean variable is set in StoreRouteElementInPrefDirVector
18557  since that catches all route elements wherever created
18558 */
18559 {
18560  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddRouteElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
18561  AnsiString(ELink) + "," + AnsiString(RouteNumber) + "," + RouteElement.LogPrefDir());
18562  GetModifiableRouteAt(11, RouteNumber).StoreRouteElementInPrefDirVector(RouteElement);
18563  Route2MultiMapInsert(0, HLoc, VLoc, ELink, RouteNumber, GetModifiableRouteAt(12, RouteNumber).PrefDirSize() - 1);
18564  Utilities->CallLogPop(408);
18565 }
18566 
18567 // ---------------------------------------------------------------------------
18568 
18569 void TAllRoutes::SetTrailingSignalsOnAutoSigsRoute(int Caller, int TrackVectorPosition, int XLinkPos)
18570 /*
18571  Enter with signal at TrackVectorElement already set to red by the passing train.
18572  Identify the route that the TrackVectorPosition is in, carry out validity checks, then call SetAllRearwardsSignals to set signals
18573  in this route and all linked rearwards routes, unless find a train (a) in the current route, in which case the signals behind it are
18574  set (and behind any other trains in the current route), but only within the current route; or (b) in a linked rear route, in which
18575  case the function sets no further signals.
18576 */
18577 {
18578  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrailingSignalsOnAutoSigsRoute," + AnsiString(TrackVectorPosition) +
18579  "," + AnsiString(XLinkPos));
18580  TRouteElementPair RouteElementPair, SecondPair, RequiredPair;
18581  TTrackElement TE = Track->TrackElementAt(159, TrackVectorPosition);
18582 
18583  RouteElementPair = GetRouteElementDataFromRoute2MultiMap(9, TE.HLoc, TE.VLoc, SecondPair);
18584  if(RouteElementPair.first == -1)
18585  {
18586  throw Exception("Error, failed to find element in SetTrailingSignalsOnAutoSigsRoute - 1");
18587  }
18588  TPrefDirElement RouteElement = GetFixedRouteAt(119, RouteElementPair.first).GetFixedPrefDirElementAt(138, RouteElementPair.second);
18589 
18590  RequiredPair = RouteElementPair;
18591  if(RouteElement.XLinkPos != XLinkPos)
18592  {
18593  if(SecondPair.first != -1)
18594  {
18595  RouteElement = GetFixedRouteAt(120, SecondPair.first).GetFixedPrefDirElementAt(139, SecondPair.second);
18596  RequiredPair = SecondPair;
18597  if(RouteElement.XLinkPos != XLinkPos)
18598  {
18599  throw Exception("Failed to find element in route in SetTrailingSignalsOnAutoSigsRoute - 2");
18600  }
18601  }
18602  else
18603  {
18604  throw Exception("Failed to find element in route in SetTrailingSignalsOnAutoSigsRoute - 3");
18605  }
18606  }
18607 // new function
18608  SetAllRearwardsSignals(5, 0, RequiredPair.first, RequiredPair.second);
18609  Utilities->CallLogPop(409);
18610 }
18611 
18612 // ---------------------------------------------------------------------------
18613 
18614 void TAllRoutes::SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber)
18615 /*
18616  This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in TrainController to set signals on
18617  the AutoSigsRoute to correspond to a train having exited the route at a continuation, and passing further signals (outside the simulated
18618  railway). Initially the last passed signal will be red, then at the first call it will change to yellow and earlier signals will change
18619  accordingly, then double yellow, then green. There are only 3 calls in all for any given route, and the AccessNumber changes from 0 to 1
18620  to 2 for successive calls.
18621  Initially Attribute is set to AccessNumber + 1 to correspond to the first signal attribute to be set, then a number of validity checks
18622  are carried out on RouteNumber. Then SetAllRearwardsSignals is called to set signals in this route and all linked rearwards routes,
18623  unless find a train (a) in the current route, in which case the signals behind it are set (and behind any other trains in the current
18624  route), but only within the current route; or (b) in a linked rear route, in which case the function sets no further signals.
18625 */
18626 {
18627  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrailingSignalsOnContinuationRoute," + AnsiString(RouteNumber) + "," +
18628  AnsiString(AccessNumber));
18629  TPrefDirElement RouteElement;
18630  int Attribute = AccessNumber + 1;
18631 // signal attributes: 0=red; 1=yellow; 2=double yellow; 3 = green
18632  int x = GetFixedRouteAt(121, RouteNumber).PrefDirSize() - 1;
18633 
18634  if(!(GetFixedRouteAt(122, RouteNumber).GetFixedPrefDirElementAt(140, x).AutoSignals))
18635  {
18636  throw Exception("Error - route not AutoSignals in SetTrailingSignalsOnContinuationRoute");
18637  }
18638  if(GetFixedRouteAt(123, RouteNumber).GetFixedPrefDirElementAt(141, x).TrackType != Continuation)
18639  {
18640  throw Exception("Error - end element not continuation in SetTrailingSignalsOnContinuationRoute");
18641  }
18642  if(GetFixedRouteAt(124, RouteNumber).GetFixedPrefDirElementAt(142, x).Config[GetFixedRouteAt(125, RouteNumber).GetFixedPrefDirElementAt(143,
18643  x).XLinkPos] != End)
18644  {
18645  throw Exception("Error - end element a continuation in SetTrailingSignalsOnContinuationRoute but End not facing right way");
18646  }
18647 // new function
18648  SetAllRearwardsSignals(6, Attribute, RouteNumber, GetFixedRouteAt(126, RouteNumber).PrefDirSize() - 1);
18649  Utilities->CallLogPop(410);
18650 }
18651 
18652 // ---------------------------------------------------------------------------
18653 
18654 void TAllRoutes::SetAllRearwardsSignals(int Caller, int Attribute, int RouteNumber, int RouteStartPosition)
18655 /*
18656  Sets signals in all linked rearwards routes from the RouteStartPosition in RouteNumber, unless find a train (a) in the current route,
18657  in which case the signals behind it are set (and behind any other trains in the current route), but only within the current route;
18658  or (b) in a linked rear route, in which case the function sets no further signals.
18659 
18660  First call SetRearwardsSignalsReturnFalseForTrain (which is only called by this function) to set signals in route RouteNumber according
18661  to the received or modified (because of the forward look for buffers or continuation) Attribute. If no train is found during this call
18662  (returns true) then check for and call SetRearwardsSignalsReturnFalseForTrain for each rearwards linked route until either reach the
18663  beginning of the last linked route or find a train on a linked rear route. If no train was found during the RouteNumber call to
18664  SetRearwardsSignalsReturnFalseForTrain then the function terminates here.
18665  However if a train was found during the RouteNumber call to SetRearwardsSignalsReturnFalseForTrain then need to continue after the
18666  train in case had just added a route segment behind a train that now forms part of a single continuous route, otherwise the signals
18667  won't be set behind the train. First the route is examined element by element from the RouteStartPosition towards the start of the
18668  route until the train is found. Then the route elements are examined from the TrainPosition towards the start of the route until the
18669  first element behind the train is found. A recursive call to this function is then made from this behind-train position, to set all
18670  signals behind the train (and behind as many trains as there are on the single route) beginning with a red signal for the first signal
18671  found behind the train.
18672 
18673  Description of SetRearwardsSignalsReturnFalseForTrain for reference:
18674  Enter with Attribute set to the value to be used (unless modified by the initial forward search - see later) for the first rearwards
18675  signal found, and with PrefDirVectorStartPosition set to the position in PrefDirVector to begin the search. BUT, don't begin with the
18676  rearward search, first search forwards from the PrefDirVectorStartPosition in case the end of the route is a buffer or continuation, and
18677  modify the Attribute accordingly UNLESS (a) train present between PrefDirVectorStartPosition & end; (b) route in
18678  ContinuationAutoSigVector (i.e. train has exited the route at a continuation but it is still affecting the signals), or (c) truncating
18679  a route.
18680 
18681  Having received or modified Attribute as above, work backwards from the PrefDirVectorStartPosition until find a train - return false, or a
18682  signal. If find a signal set its Attribute to the current Attribute value up to a maximum of 3, and replot the signal as well as
18683  the required route and direction (if required) graphics, then increment Attribute up to a max. of 3 [addition at v2.9.2: if signal or element beyond
18684  it is in a locked route then set signal to red & change Attribute to 0 - this fault reported by Simon Banham 21/07/21 as an image]. and continue working backwards
18685  for the next signal (or train - return false as before) and so on. On completion Attribute is passed back from the function as a
18686  reference. If no train is found before the beginning of the route is reached the function returns true
18687 
18688 */
18689 {
18690  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetAllRearwardsSignals," + AnsiString(Attribute) + "," +
18691  AnsiString(RouteNumber) + "," + AnsiString(RouteStartPosition));
18692  TPrefDirElement FirstElement = GetFixedRouteAt(127, RouteNumber).GetFixedPrefDirElementAt(144, 0);
18693  int RearwardLinkedRouteNumber;
18694 
18695  Track->LCFoundInRouteBuildingFlag = false; // only examined for the new route segment, not for linked routes
18696  if(GetFixedRouteAt(128, RouteNumber).SetRearwardsSignalsReturnFalseForTrain(1, Attribute, RouteStartPosition)) // updates Attribute to 1+ final
18697  // signal value in the route for use in further linked routes
18698  {
18699  if(FirstElement.Conn[FirstElement.ELinkPos] > -1) // GetRouteTypeAndNumber tests for this but check here to avoid call if == -1
18700  {
18701  while(GetRouteTypeAndNumber(6, FirstElement.Conn[FirstElement.ELinkPos], FirstElement.ConnLinkPos[FirstElement.ELinkPos],
18702  RearwardLinkedRouteNumber) != TAllRoutes::NoRoute)
18703  {
18704  if(!(GetFixedRouteAt(129, RearwardLinkedRouteNumber).SetRearwardsSignalsReturnFalseForTrain(2, Attribute, AllRoutes->GetFixedRouteAt(130,
18705  RearwardLinkedRouteNumber).PrefDirSize() - 1)))
18706  {
18707  break;
18708  }
18709  // in above the RouteSettingFlag is set to false because this call is for routes that lie behind the route that is being set so don't want to
18710  // flash LCs on those routes
18711  FirstElement = AllRoutes->GetFixedRouteAt(131, RearwardLinkedRouteNumber).GetFixedPrefDirElementAt(145, 0);
18712  }
18713  }
18714  }
18715  else
18716  // found a train in the entry route before the beginning of the route, so need to continue after the train in case had just added a
18717  // route segment behind a train that now forms part of a single continuous route, otherwise the signals won't be set behind the train
18718  {
18719  int TrainID, TrainPosition, BehindTrainPosition;
18720  bool FoundTrain = false, BehindTrain = false;
18721  for(int x = RouteStartPosition; x >= 0; x--) // first step back from start position until find the train....
18722  {
18723  TPrefDirElement PrefDirElement = GetFixedRouteAt(132, RouteNumber).GetFixedPrefDirElementAt(146, x);
18724  TTrackElement TrackElement = Track->TrackElementAt(160, PrefDirElement.TrackVectorPosition);
18725  TrainID = TrackElement.TrainIDOnElement;
18726  if(TrackElement.TrackType == Bridge)
18727  {
18728  if(PrefDirElement.XLinkPos < 2)
18729  {
18730  TrainID = TrackElement.TrainIDOnBridgeTrackPos01;
18731  }
18732  else
18733  {
18734  TrainID = TrackElement.TrainIDOnBridgeTrackPos23;
18735  }
18736  }
18737  if(TrainID == -1)
18738  {
18739  continue;
18740  }
18741  else
18742  {
18743  FoundTrain = true;
18744  TrainPosition = x;
18745  break;
18746  }
18747  }
18748  if(FoundTrain && (TrainPosition > 1)) // if TrainPosition 1 or less then no route behind the train so can stop
18749  {
18750  for(int x = TrainPosition; x >= 0; x--) // then step back from that position until find element behind the train - ignore any
18751  {
18752  // signals that the train itself is straddling, need the first signal behind the train to be set to red, when the train passes
18753  // the signal it's straddling the rearwards signals will be reset again. Even if there are two or more trains adjacent still
18754  // need the element behind the rearmost train.
18755  TPrefDirElement PrefDirElement = GetFixedRouteAt(133, RouteNumber).GetFixedPrefDirElementAt(147, x);
18756  TTrackElement TrackElement = Track->TrackElementAt(161, PrefDirElement.TrackVectorPosition);
18757  TrainID = TrackElement.TrainIDOnElement;
18758  if(TrackElement.TrackType == Bridge)
18759  {
18760  if(PrefDirElement.XLinkPos < 2)
18761  {
18762  TrainID = TrackElement.TrainIDOnBridgeTrackPos01;
18763  }
18764  else
18765  {
18766  TrainID = TrackElement.TrainIDOnBridgeTrackPos23;
18767  }
18768  }
18769  if(TrainID != -1)
18770  {
18771  continue; // still on train
18772  }
18773  else
18774  {
18775  BehindTrain = true;
18776  BehindTrainPosition = x;
18777  break;
18778  }
18779  }
18780  if(BehindTrain) // then carry out a recursive rearward signal setting behind the train &
18781  // so on for as many trains as there are on the single route
18782  {
18783  SetAllRearwardsSignals(7, 0, RouteNumber, BehindTrainPosition); // false because can't set a route where there is a train
18784  // first signal behind train to be red
18785  }
18786  }
18787  }
18788  Utilities->CallLogPop(411);
18789 }
18790 
18791 // ---------------------------------------------------------------------------
18792 
18793 bool TAllRoutes::RouteLockingRequired(int Caller, int RouteNumber, int RouteTruncatePosition)
18794 {
18795 /* Locked if a train moving in the direction of the route within 3 signals back from truncate point (on the route itself or any linked routes, or on the element
18796  immediately before the start of the route or linked route - this because train cancels route elements that it touches) unless
18797  first signal is red, then OK
18798 */
18799  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RouteLockingRequired," + AnsiString(RouteNumber) + "," +
18800  AnsiString(RouteTruncatePosition));
18801  int SignalCount = 0, TrainID, RearwardLinkedRouteNumber, StartPosition = RouteTruncatePosition;
18802  TOneRoute CurrentRoute = GetFixedRouteAt(134, RouteNumber);
18803  TPrefDirElement PrefDirElement, FirstElement;
18804  TTrackElement TrackElement;
18805  bool ExamineRoute = true;
18806 
18807  while(ExamineRoute)
18808  {
18809  for(int x = StartPosition; x >= 0; x--) //work back along the route from the truncate point
18810  {
18811  PrefDirElement = CurrentRoute.GetFixedPrefDirElementAt(148, x);
18812  TrackElement = Track->TrackElementAt(162, PrefDirElement.TrackVectorPosition);
18813  TrainID = TrackElement.TrainIDOnElement;
18814  if(TrackElement.TrackType == Bridge)
18815  {
18816  if(PrefDirElement.XLinkPos < 2)
18817  {
18818  TrainID = TrackElement.TrainIDOnBridgeTrackPos01;
18819  }
18820  else
18821  {
18822  TrainID = TrackElement.TrainIDOnBridgeTrackPos23;
18823  }
18824  }
18825  if(TrainID > -1)
18826  {
18827  if(TrainController->TrainVectorAtIdent(36, TrainID).Stopped())
18828  {
18829  //any trains further back in route will be protected by the red signal behind the stopped train
18830  Utilities->CallLogPop(412);
18831  return(false);
18832  }
18833  //added at v2.4.2 for trains facing the wrong way & moving but haven't moved a half element yet so route still intact
18834  if(TrainController->TrainVectorAtIdent(49, TrainID).GetLeadElement() != PrefDirElement.TrackVectorPosition) //if it isn't then the train is facing the
18835  //other way & can cancel the route
18836  {
18837  Utilities->CallLogPop(2203);
18838  return(false);
18839  }
18840  Utilities->CallLogPop(1961); //otherwise need to lock the route as have found a train on the route (trains forward of the truncate point caught by
18841  return(true); //TrainOccupyingRoute which is outside this function but also causes route locking)
18842  }
18843  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal) // XLinkPos because signal has to be facing same direction as PrefDir to count
18844  {
18845  if(TrackElement.Attribute == 0)
18846  {
18847  Utilities->CallLogPop(413);
18848  return(false); // OK, red signal in front of a train
18849  }
18850  SignalCount++;
18851  if(SignalCount >= 3)
18852  {
18853  Utilities->CallLogPop(414);
18854  return(false);
18855  }
18856  }
18857  if(PrefDirElement.Config[PrefDirElement.ELinkPos] == End) // buffer or continuation & no train
18858  // ElinkPos because working back along PrefDir to beginning
18859  {
18860  Utilities->CallLogPop(415);
18861  return(false); // test - set to true to create a locked buffer-ended route, false for normal use
18862  }
18863  }
18864  //now look at linked rearwards routes
18865  FirstElement = CurrentRoute.GetFixedPrefDirElementAt(149, 0);
18866  StartPosition = CurrentRoute.PrefDirSize() - 1;
18867  if(GetRouteTypeAndNumber(7, FirstElement.Conn[FirstElement.ELinkPos], FirstElement.ConnLinkPos[FirstElement.ELinkPos],
18868  RearwardLinkedRouteNumber) != TAllRoutes::NoRoute)
18869  {
18870  CurrentRoute = GetFixedRouteAt(135, RearwardLinkedRouteNumber);
18871  ExamineRoute = true;
18872  StartPosition = GetFixedRouteAt(136, RearwardLinkedRouteNumber).PrefDirSize() - 1;
18873  }
18874  else
18875  {
18876  // here check for a train on the element immediately before the first route element
18877  TTrackElement PriorTrackElement = Track->TrackElementAt(489, FirstElement.Conn[FirstElement.ELinkPos]);
18878  TrainID = PriorTrackElement.TrainIDOnElement;
18879  if(PriorTrackElement.TrackType == Bridge)
18880  {
18881  if(FirstElement.ConnLinkPos[FirstElement.ELinkPos] < 2)
18882  {
18883  TrainID = PriorTrackElement.TrainIDOnBridgeTrackPos01;
18884  }
18885  else
18886  {
18887  TrainID = PriorTrackElement.TrainIDOnBridgeTrackPos23;
18888  }
18889  }
18890  if(TrainID > -1)
18891  {
18892  if(TrainController->TrainVectorAtIdent(37, TrainID).Stopped())
18893  {
18894  Utilities->CallLogPop(748);
18895  return(false);
18896  }
18897  //added at v2.4.2 for trains facing the wrong way on the prior element & moving but haven't moved a half element yet
18898  if(TrainController->TrainVectorAtIdent(50, TrainID).GetLeadElement() != FirstElement.Conn[FirstElement.ELinkPos]) //if it isn't then the train is facing the
18899  //other way & can cancel the route
18900  {
18901  Utilities->CallLogPop(2204);
18902  return(false);
18903  }
18904  Utilities->CallLogPop(1962);
18905  return(true); //otherwise need to lock the route
18906  }
18907  ExamineRoute = false;
18908  }
18909  }
18910 // if reach beginning of all rear routes without finding a train and there aren't 3 signals then truncate the route
18911 // as trains running on unrouted lines are already at risk of wrong points etc so no benefit locking the route
18912  Utilities->CallLogPop(416);
18913  return(false);
18914 }
18915 
18916 // ---------------------------------------------------------------------------
18917 
18918 bool TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos,
18919  TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
18920 {
18921  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber," +
18922  AnsiString(TrackVectorPosition) + "," + AnsiString(XLinkPos));
18923  TPrefDirElement InternalPrefDirElement; // blank element
18924 
18925  PrefDirElement = InternalPrefDirElement;
18926  if(LockedRouteVector.empty())
18927  {
18928  Utilities->CallLogPop(417);
18929  return(false);
18930  }
18931 // make sure at least one locked route record is still valid - train may have removed it, if last element still present locked route still exists,
18932 // even if some elements have been removed from the front by a train
18933  bool InLockedRoute = false;
18934 
18935  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
18936  {
18937  if(TrackIsInARoute(14, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos))
18938  {
18939  // end of route can't be points, crossover or bridge so danger of route being on the other track of a 2-track element
18940  // doesn't arise)
18941  InLockedRoute = true;
18942  break;
18943  }
18944  }
18945  if(!InLockedRoute)
18946  {
18947  Utilities->CallLogPop(418);
18948  return(false);
18949  }
18950  int RouteNumber, VectorCount = 0;
18951  TRouteType RouteType;
18952 
18953  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
18954  {
18955  RouteType = GetRouteTypeAndNumber(8, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos, RouteNumber);
18956  if(RouteType == NoRoute)
18957  {
18958  continue;
18959  }
18960  if((GetFixedRouteAt(137, RouteNumber).GetFixedPrefDirElementAt(150, GetFixedRouteAt(138, RouteNumber).PrefDirSize() - 1).TrackVectorPosition != (int)
18961  LRVIT->LastTrackVectorPosition) || (GetFixedRouteAt(139, RouteNumber).GetFixedPrefDirElementAt(151,
18962  GetFixedRouteAt(140, RouteNumber).PrefDirSize() - 1).XLinkPos != LRVIT->LastXLinkPos))
18963  {
18964  throw Exception
18965  ("Error, last element in locked route doesn't correspond with last element in associated route in IsElementInLockedRouteGetPrefDirElement");
18966  }
18967  for(int x = GetFixedRouteAt(141, RouteNumber).PrefDirSize() - 1; x >= 0; x--)
18968  {
18969  InternalPrefDirElement = GetFixedRouteAt(142, RouteNumber).GetFixedPrefDirElementAt(152, x);
18970  if(InternalPrefDirElement.TrackVectorPosition != (int)LRVIT->TruncateTrackVectorPosition)
18971  {
18972  if((InternalPrefDirElement.TrackVectorPosition == TrackVectorPosition) && (InternalPrefDirElement.XLinkPos == XLinkPos))
18973  {
18974  PrefDirElement = InternalPrefDirElement;
18975  LockedVectorNumber = VectorCount;
18976  Utilities->CallLogPop(419);
18977  return(true);
18978  }
18979  }
18980  else if(InternalPrefDirElement.TrackVectorPosition == (int)LRVIT->TruncateTrackVectorPosition)
18981  {
18982  if((InternalPrefDirElement.TrackVectorPosition == TrackVectorPosition) && (InternalPrefDirElement.XLinkPos == XLinkPos))
18983  {
18984  PrefDirElement = InternalPrefDirElement;
18985  LockedVectorNumber = VectorCount;
18986  Utilities->CallLogPop(420);
18987  return(true);
18988  }
18989  else
18990  {
18991  break; // reached & tested LRVIT->TruncateTrackVectorPosition for a match so don't want to go any further for this route
18992  }
18993  }
18994  }
18995  VectorCount++;
18996  }
18997  Utilities->CallLogPop(421);
18998  return(false);
18999 }
19000 
19001 // ---------------------------------------------------------------------------
19002 
19004 {
19005  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteVectorNumber," + AnsiString(RouteID.GetInt()));
19006  for(unsigned int x = 0; x < AllRoutesSize(); x++)
19007  {
19008  if(GetFixedRouteAt(157, x).RouteID == RouteID.GetInt())
19009  {
19010  Utilities->CallLogPop(963);
19011  return(x);
19012  }
19013  }
19014  throw Exception("Error, failed to find RouteID in GetRouteVectorNumber for ID: " + AnsiString(RouteID.GetInt()));
19015 }
19016 
19017 // ---------------------------------------------------------------------------
19018 
19020 // added at v1.3.1 after an error was generated when operating Ian Walker's Chiltern Railway
19021 // found to be due to a route having been removed by a train moving in the wrong direction after the route was selected but before it completed (i.e. route removed while flashing)
19022 {
19023  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsThereARouteAtIDNumber," + AnsiString(RouteID.GetInt()));
19024  for(unsigned int x = 0; x < AllRoutesSize(); x++)
19025  {
19026  if(GetFixedRouteAt(45, x).RouteID == RouteID.GetInt())
19027  {
19028  Utilities->CallLogPop(2039);
19029  return(true);
19030  }
19031  }
19032  Utilities->CallLogPop(2040);
19033  return(false);
19034 }
19035 
19036 // ---------------------------------------------------------------------------
19037 
19039 {
19040  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedRouteAtIDNumber," + AnsiString(RouteID.GetInt()));
19041  for(unsigned int x = 0; x < AllRoutesSize(); x++)
19042  {
19043  if(GetFixedRouteAt(163, x).RouteID == RouteID.GetInt())
19044  {
19045  Utilities->CallLogPop(964);
19046  return(GetFixedRouteAt(159, x));
19047  }
19048  }
19049  throw Exception("Error, failed to find RouteID in GetFixedRouteAtIDNumber for ID: " + AnsiString(RouteID.GetInt()));
19050 }
19051 
19052 // ---------------------------------------------------------------------------
19053 
19055 {
19056  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableRouteATIDNumber," + AnsiString(RouteID.GetInt()));
19057  for(unsigned int x = 0; x < AllRoutesSize(); x++)
19058  {
19059  if(GetFixedRouteAt(164, x).RouteID == RouteID.GetInt())
19060  {
19061  Utilities->CallLogPop(965);
19062  return(GetModifiableRouteAt(15, x));
19063  }
19064  }
19065  throw Exception("Error, failed to find RouteID in GetModifiableRouteAtIDNumber for ID: " + AnsiString(RouteID.GetInt()));
19066 }
19067 
19068 // ---------------------------------------------------------------------------
19069 
19070 void TAllRoutes::SaveRoutes(int Caller, std::ofstream &OutFile)
19071 {
19072  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveRoutes");
19073  Utilities->SaveFileInt(OutFile, AllRoutesSize()); // so know how many to reload
19074  Utilities->SaveFileInt(OutFile, NextRouteID);
19075  for(unsigned int x = 0; x < AllRoutesSize(); x++)
19076  {
19077  TOneRoute OneRoute = GetFixedRouteAt(165, x);
19078  Utilities->SaveFileInt(OutFile, OneRoute.RouteID);
19079  OneRoute.SavePrefDirVector(6, OutFile);
19080  }
19081  Utilities->CallLogPop(1442);
19082 }
19083 
19084 // ---------------------------------------------------------------------------
19085 
19086 bool TAllRoutes::LoadRoutes(int Caller, std::ifstream &InFile)
19087 {
19088  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadRoutes");
19089  int NumberOfRoutes;
19090 
19091  NumberOfRoutes = Utilities->LoadFileInt(InFile);
19092  NextRouteID = Utilities->LoadFileInt(InFile);
19093  for(int x = 0; x < NumberOfRoutes; x++)
19094  {
19095  TOneRoute OneRoute; // empty route
19096  OneRoute.RouteID = Utilities->LoadFileInt(InFile);
19097  OneRoute.LoadPrefDir(2, InFile);
19099  {
19100  StoreOneRouteAfterSessionLoad(0, &OneRoute);
19101  }
19102  else
19103  {
19104  Utilities->CallLogPop(1443);
19105  return(false);
19106  }
19107  }
19108  Utilities->CallLogPop(1444);
19109  return(true);
19110 }
19111 
19112 // ---------------------------------------------------------------------------
19113 bool TAllRoutes::CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
19114 {
19115  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckRoutes," + AnsiString(NumberOfActiveElements));
19116  int NumberOfRoutes = Utilities->LoadFileInt(InFile);
19117 
19118  if((NumberOfRoutes < 0) || (NumberOfRoutes > 5000))
19119  {
19120  Utilities->CallLogPop(1445);
19121  return(false);
19122  }
19123  int NextID = Utilities->LoadFileInt(InFile);
19124 
19125  if((NextID < 0) || (NextID > 1000000))
19126  {
19127  Utilities->CallLogPop(1446);
19128  return(false);
19129  }
19130  for(int x = 0; x < NumberOfRoutes; x++)
19131  {
19132  int RouteID = Utilities->LoadFileInt(InFile);
19133  if((RouteID < 0) || (RouteID > 20000))
19134  {
19135  Utilities->CallLogPop(1447);
19136  return(false);
19137  }
19138  TOneRoute OneRoute; // create an empty route so CheckOnePrefDir can be called
19139  if(!(OneRoute.CheckOnePrefDir(3, NumberOfActiveElements, InFile)))
19140  {
19141  Utilities->CallLogPop(1448);
19142  return(false);
19143  }
19144  }
19145  Utilities->CallLogPop(1449);
19146  return(true);
19147 }
19148 
19149 // ---------------------------------------------------------------------------
19150 
19151 bool TAllRoutes::CheckForLoopingRoute(int Caller, int EndPosition, int EndXLinkPos, int StartPosition)
19152 {
19153  // return true for a loop
19154  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckForLoopingRoute," + AnsiString(EndPosition) + "," +
19155  AnsiString(StartPosition));
19156  if(EndPosition == StartPosition)
19157  {
19158  Utilities->CallLogPop(1839);
19159  return(true); // shouldn't happen but treat as a loop if does
19160  }
19161 // begin at EndPosition & EndXLinkPos & work forwards until reach end of route (return false) or StartElement (return true)
19162  int TVPos = EndPosition; //TVPos is the current element and NewTVPos is the element it connects to
19163  int LkPos = EndXLinkPos; //LkPos is the exit link and NewLkPos is the entry link of the linked element
19164 
19165  while(TrackIsInARoute(15, TVPos, LkPos))
19166  {
19167  int NewTVPos = Track->TrackElementAt(826, TVPos).Conn[LkPos]; //see above
19168  int NewLkPos = -1;
19169  if(NewTVPos > -1)
19170  {
19171  NewLkPos = Track->TrackElementAt(827, TVPos).ConnLinkPos[LkPos]; // this is the entry link pos
19172  if(NewLkPos == -1)
19173  {
19174  Utilities->CallLogPop(1840);
19175  return(true); // shouldn't arise but treat as loop if does
19176  }
19177  }
19178  else // reached a buffer or continuation
19179  {
19180  Utilities->CallLogPop(1841);
19181  return(false);
19182  }
19183 //Error found by Xeon notified by email 13/10/20.
19184 //Need to make sure there is a route with the new entry link NewLkPos on the next element (TrackIsInARoute normally used where it doesn't matter which track a route
19185 //is on - except for bridges). But here a route can end at a trailing point leg or a crossover and if so it doesn't link to the route on the other track, and needs to
19186 //return false. Without the new check below the program gets stuck in an endless loop, which is the error that Xeon found.
19187 //If there isn't a route at all on the next element then it would return false at the next iteration so can return false here.
19188 //New check added for v2.6.0
19189 //Note: Could probably use GetRouteTypeAndNumber in place of TrackIsInARoute in the while statement above and dispense with this new check, but I prefer to keep mods as simple
19190 //as possible in case there are other unforeseen effects.
19191  int RouteNumber; //dummy, not used
19192  if(GetRouteTypeAndNumber(36, NewTVPos, NewLkPos, RouteNumber) == NoRoute)
19193  {
19194  Utilities->CallLogPop(2241);
19195  return(false);
19196  }
19197  //now make the connected element the current element, read across the TV number and determine the exit link
19198  TVPos = NewTVPos;
19199  if(Track->TrackElementAt(828, TVPos).TrackType == Points)
19200  {
19201  if((NewLkPos == 0) || (NewLkPos == 2)) // leading points
19202  {
19203  if(Track->TrackElementAt(829, TVPos).Attribute == 0)
19204  {
19205  LkPos = 1;
19206  }
19207  else
19208  {
19209  LkPos = 3;
19210  }
19211  }
19212  else
19213  {
19214  LkPos = 0;
19215  }
19216  }
19217  else
19218  {
19219  LkPos = Track->GetNonPointsOppositeLinkPos(NewLkPos);
19220  }
19221  if(TVPos == StartPosition)
19222  {
19223  Utilities->CallLogPop(1842);
19224  return(true); // it is a loop
19225  }
19226  }
19227  Utilities->CallLogPop(1843);
19228  return(false); // reached end of route so not a loop
19229 }
19230 
19231 // ---------------------------------------------------------------------------
19232 
19233 bool TAllRoutes::DiagonalFouledByRouteOrTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
19234 /*
19235  Track geometry allows diagonals to cross without occupying the same track element, so when
19236  route plotting it is necessary to check if there is an existing route or a train on such a crossing
19237  diagonal. Returns true for a fouled diagonal. Enter with H & V set for the element whose diagonal
19238  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
19239  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
19240  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
19241  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
19242  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
19243  Each of these is examined in turn for each route element in the relevant position.
19244 
19245  NOTE: Originally this failed to detect a train fouling a diagonal. v1.2.0 checks for a train present on a
19246  crossing diagonal element using a new bool function TTrack::TrainOnLink(int HLoc, int VLoc, int Link)
19247  that returns false in all cases (including elements & links not present) except train present.
19248 */
19249 {
19250  int TrainID; // not used in this function
19251 
19252  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByRouteOrTrain," + AnsiString(HLoc) + "," +
19253  AnsiString(VLoc) + "," + AnsiString(DiagonalLinkNumber));
19254  TPrefDirElement TempPrefDirElement;
19255  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
19256 
19257  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(4, HLoc - 1, VLoc, SecondPair);
19258  if(FirstPair.first > -1)
19259  {
19260  TempPrefDirElement = AllRoutes->GetFixedRouteAt(50, FirstPair.first).GetFixedPrefDirElementAt(70, FirstPair.second);
19261  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19262  {
19263  Utilities->CallLogPop(310);
19264  return(true);
19265  }
19266  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19267  {
19268  Utilities->CallLogPop(311);
19269  return(true);
19270  }
19271  }
19272  if(SecondPair.first > -1)
19273  {
19274  TempPrefDirElement = AllRoutes->GetFixedRouteAt(51, SecondPair.first).GetFixedPrefDirElementAt(71, SecondPair.second);
19275  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19276  {
19277  Utilities->CallLogPop(312);
19278  return(true);
19279  }
19280  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19281  {
19282  Utilities->CallLogPop(313);
19283  return(true);
19284  }
19285  }
19286  if(((DiagonalLinkNumber == 1) && Track->TrainOnLink(0, HLoc - 1, VLoc, 3, TrainID)) || ((DiagonalLinkNumber == 7) && Track->TrainOnLink(1, HLoc - 1, VLoc,
19287  9, TrainID)))
19288  {
19289  Utilities->CallLogPop(1997);
19290  return(true);
19291  }
19292  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(5, HLoc, VLoc - 1, SecondPair);
19293  if(FirstPair.first > -1)
19294  {
19295  TempPrefDirElement = AllRoutes->GetFixedRouteAt(52, FirstPair.first).GetFixedPrefDirElementAt(72, FirstPair.second);
19296  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19297  {
19298  Utilities->CallLogPop(314);
19299  return(true);
19300  }
19301  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19302  {
19303  Utilities->CallLogPop(315);
19304  return(true);
19305  }
19306  }
19307  if(SecondPair.first > -1)
19308  {
19309  TempPrefDirElement = AllRoutes->GetFixedRouteAt(53, SecondPair.first).GetFixedPrefDirElementAt(73, SecondPair.second);
19310  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19311  {
19312  Utilities->CallLogPop(316);
19313  return(true);
19314  }
19315  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19316  {
19317  Utilities->CallLogPop(317);
19318  return(true);
19319  }
19320  }
19321  if(((DiagonalLinkNumber == 1) && Track->TrainOnLink(2, HLoc, VLoc - 1, 7, TrainID)) || ((DiagonalLinkNumber == 3) && Track->TrainOnLink(3, HLoc, VLoc - 1,
19322  9, TrainID)))
19323  {
19324  Utilities->CallLogPop(1998);
19325  return(true);
19326  }
19327  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(6, HLoc + 1, VLoc, SecondPair);
19328  if(FirstPair.first > -1)
19329  {
19330  TempPrefDirElement = AllRoutes->GetFixedRouteAt(54, FirstPair.first).GetFixedPrefDirElementAt(74, FirstPair.second);
19331  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19332  {
19333  Utilities->CallLogPop(318);
19334  return(true);
19335  }
19336  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19337  {
19338  Utilities->CallLogPop(319);
19339  return(true);
19340  }
19341  }
19342  if(SecondPair.first > -1)
19343  {
19344  TempPrefDirElement = AllRoutes->GetFixedRouteAt(55, SecondPair.first).GetFixedPrefDirElementAt(75, SecondPair.second);
19345  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19346  {
19347  Utilities->CallLogPop(320);
19348  return(true);
19349  }
19350  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19351  {
19352  Utilities->CallLogPop(321);
19353  return(true);
19354  }
19355  }
19356  if(((DiagonalLinkNumber == 3) && Track->TrainOnLink(4, HLoc + 1, VLoc, 1, TrainID)) || ((DiagonalLinkNumber == 9) && Track->TrainOnLink(5, HLoc + 1, VLoc,
19357  7, TrainID)))
19358  {
19359  Utilities->CallLogPop(1999);
19360  return(true);
19361  }
19362  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(7, HLoc, VLoc + 1, SecondPair);
19363  if(FirstPair.first > -1)
19364  {
19365  TempPrefDirElement = AllRoutes->GetFixedRouteAt(56, FirstPair.first).GetFixedPrefDirElementAt(76, FirstPair.second);
19366  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19367  {
19368  Utilities->CallLogPop(322);
19369  return(true);
19370  }
19371  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19372  {
19373  Utilities->CallLogPop(323);
19374  return(true);
19375  }
19376  }
19377  if(SecondPair.first > -1)
19378  {
19379  TempPrefDirElement = AllRoutes->GetFixedRouteAt(57, SecondPair.first).GetFixedPrefDirElementAt(77, SecondPair.second);
19380  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19381  {
19382  Utilities->CallLogPop(324);
19383  return(true);
19384  }
19385  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19386  {
19387  Utilities->CallLogPop(325);
19388  return(true);
19389  }
19390  }
19391  if(((DiagonalLinkNumber == 7) && Track->TrainOnLink(6, HLoc, VLoc + 1, 1, TrainID)) || ((DiagonalLinkNumber == 9) && Track->TrainOnLink(7, HLoc, VLoc + 1,
19392  3, TrainID)))
19393  {
19394  Utilities->CallLogPop(2000);
19395  return(true);
19396  }
19397  Utilities->CallLogPop(326);
19398  return(false);
19399 }
19400 
19401 // ---------------------------------------------------------------------------
19402 
19403 bool TAllRoutes::DiagonalFouledByRoute(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
19404 /*
19405  As above but checks for a route only (may or may not be a train). Enter with H & V set for the element whose diagonal
19406  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
19407  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
19408  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
19409  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
19410  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
19411  Each of these is examined in turn for each route element in the relevant position.
19412 */
19413 {
19414  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByRoute," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
19415  "," + AnsiString(DiagonalLinkNumber));
19416  TPrefDirElement TempPrefDirElement;
19417  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
19418 
19419  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(17, HLoc - 1, VLoc, SecondPair);
19420  if(FirstPair.first > -1)
19421  {
19422  TempPrefDirElement = AllRoutes->GetFixedRouteAt(197, FirstPair.first).GetFixedPrefDirElementAt(233, FirstPair.second);
19423  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19424  {
19425  Utilities->CallLogPop(2010);
19426  return(true);
19427  }
19428  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19429  {
19430  Utilities->CallLogPop(2011);
19431  return(true);
19432  }
19433  }
19434  if(SecondPair.first > -1)
19435  {
19436  TempPrefDirElement = AllRoutes->GetFixedRouteAt(198, SecondPair.first).GetFixedPrefDirElementAt(234, SecondPair.second);
19437  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19438  {
19439  Utilities->CallLogPop(2012);
19440  return(true);
19441  }
19442  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19443  {
19444  Utilities->CallLogPop(2013);
19445  return(true);
19446  }
19447  }
19448  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(18, HLoc, VLoc - 1, SecondPair);
19449  if(FirstPair.first > -1)
19450  {
19451  TempPrefDirElement = AllRoutes->GetFixedRouteAt(199, FirstPair.first).GetFixedPrefDirElementAt(235, FirstPair.second);
19452  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19453  {
19454  Utilities->CallLogPop(2014);
19455  return(true);
19456  }
19457  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19458  {
19459  Utilities->CallLogPop(2015);
19460  return(true);
19461  }
19462  }
19463  if(SecondPair.first > -1)
19464  {
19465  TempPrefDirElement = AllRoutes->GetFixedRouteAt(200, SecondPair.first).GetFixedPrefDirElementAt(236, SecondPair.second);
19466  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19467  {
19468  Utilities->CallLogPop(2016);
19469  return(true);
19470  }
19471  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19472  {
19473  Utilities->CallLogPop(2017);
19474  return(true);
19475  }
19476  }
19477  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(19, HLoc + 1, VLoc, SecondPair);
19478  if(FirstPair.first > -1)
19479  {
19480  TempPrefDirElement = AllRoutes->GetFixedRouteAt(201, FirstPair.first).GetFixedPrefDirElementAt(237, FirstPair.second);
19481  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19482  {
19483  Utilities->CallLogPop(2018);
19484  return(true);
19485  }
19486  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19487  {
19488  Utilities->CallLogPop(2019);
19489  return(true);
19490  }
19491  }
19492  if(SecondPair.first > -1)
19493  {
19494  TempPrefDirElement = AllRoutes->GetFixedRouteAt(202, SecondPair.first).GetFixedPrefDirElementAt(238, SecondPair.second);
19495  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19496  {
19497  Utilities->CallLogPop(2020);
19498  return(true);
19499  }
19500  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19501  {
19502  Utilities->CallLogPop(2021);
19503  return(true);
19504  }
19505  }
19506  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(20, HLoc, VLoc + 1, SecondPair);
19507  if(FirstPair.first > -1)
19508  {
19509  TempPrefDirElement = AllRoutes->GetFixedRouteAt(203, FirstPair.first).GetFixedPrefDirElementAt(239, FirstPair.second);
19510  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19511  {
19512  Utilities->CallLogPop(2022);
19513  return(true);
19514  }
19515  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19516  {
19517  Utilities->CallLogPop(2023);
19518  return(true);
19519  }
19520  }
19521  if(SecondPair.first > -1)
19522  {
19523  TempPrefDirElement = AllRoutes->GetFixedRouteAt(204, SecondPair.first).GetFixedPrefDirElementAt(240, SecondPair.second);
19524  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19525  {
19526  Utilities->CallLogPop(2024);
19527  return(true);
19528  }
19529  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19530  {
19531  Utilities->CallLogPop(2025);
19532  return(true);
19533  }
19534  }
19535  Utilities->CallLogPop(2026);
19536  return(false);
19537 }
19538 
19539 // ---------------------------------------------------------------------------
TTrain::LinkOccupied
bool LinkOccupied(int Caller, int TrackVectorPosition, int LinkNumber)
Added at v1.2.0: true if any part of train on specific link, false otherwise, including no link prese...
Definition: TrainUnit.cpp:8548
TRailGraphics::gl70
Graphics::TBitmap * gl70
Definition: GraphicUnit.h:691
TRailGraphics::bm72CallingOn
Graphics::TBitmap * bm72CallingOn
Definition: GraphicUnit.h:477
TAllRoutes::TrackIsInARoute
bool TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:17648
TPrefDirRoute
TPrefDirRoute
< used in TOnePrefDir::PrefDirMarker to indicate whether the function is being called for a preferred...
Definition: TrackUnit.h:1284
TRailGraphics::sm120
Graphics::TBitmap * sm120
Definition: GraphicUnit.h:931
TRailGraphics::bm7
Graphics::TBitmap * bm7
Definition: GraphicUnit.h:464
TOnePrefDir::LastElementPtr
TPrefDirVectorIterator LastElementPtr(int Caller)
Return a pointer to the last element in the vector.
Definition: TrackUnit.cpp:11419
TRailGraphics::gl58
Graphics::TBitmap * gl58
Definition: GraphicUnit.h:677
TRailGraphics::LCLHSVerMan
Graphics::TBitmap * LCLHSVerMan
Definition: GraphicUnit.h:744
TUserGraphicItem::UserGraphic
TPicture * UserGraphic
Definition: DisplayUnit.h:36
TRailGraphics::gl145
Graphics::TBitmap * gl145
Definition: GraphicUnit.h:627
TRailGraphics::gl102
Graphics::TBitmap * gl102
Definition: GraphicUnit.h:579
TTrack::UserGraphicVectorAt
TUserGraphicItem & UserGraphicVectorAt(int Caller, int At)
A range-checked version of UserGraphicVector.at(At)
Definition: TrackUnit.cpp:11392
TGraphicElement::HPos
int HPos
Definition: TrackUnit.h:432
TTrack::GapVLoc
int GapVLoc
record gap setting info
Definition: TrackUnit.h:566
TTextItem::VPos
int VPos
the vertical position on the railway
Definition: TextUnit.h:50
TDisplay::DisplayOffsetHHome
static int DisplayOffsetHHome
the horizontal offset of the 'Home' display
Definition: DisplayUnit.h:81
TRailGraphics::bm11
Graphics::TBitmap * bm11
Definition: GraphicUnit.h:353
TRailGraphics::sm99
Graphics::TBitmap * sm99
Definition: GraphicUnit.h:889
TTrack::ResetGapsFromGapMap
bool ResetGapsFromGapMap(int Caller)
Called by RepositionAndMapTrack to reset the connecting elements of all set gaps (their TrackVector p...
Definition: TrackUnit.cpp:5535
TOnePrefDir::RebuildPrefDirVector
void RebuildPrefDirVector(int Caller)
Called after the track vector has been rebuilt following linking, to rebuild the preferred direction ...
Definition: TrackUnit.cpp:12938
TRailGraphics::sm129
Graphics::TBitmap * sm129
Definition: GraphicUnit.h:786
TFixedTrackPiece
Definition: TrackUnit.h:82
TFixedTrackPiece::PlotFixedTrackElement
void PlotFixedTrackElement(int Caller, int HLocInput, int VLocInput) const
Plot the element on the railway display at position HLocInput & VLocInput.
Definition: TrackUnit.cpp:127
TAllRoutes::LockedRouteVector
TLockedRouteVector LockedRouteVector
the vector that stores all the locked routes on the railway
Definition: TrackUnit.h:1690
TUtilities::LoadFileString
AnsiString LoadFileString(std::ifstream &InFile)
loads a string value from the file
Definition: Utilities.cpp:190
TTrack::LNDone2MultiMap
TLNDone2MultiMap LNDone2MultiMap
multimap of processed location name elements (see type for more information above)
Definition: TrackUnit.h:790
TTextHandler::RebuildFromTextVector
void RebuildFromTextVector(int Caller, TDisplay *Disp)
display all text items in TextVector on the screen
Definition: TextUnit.cpp:425
TRailGraphics::sm72
Graphics::TBitmap * sm72
Definition: GraphicUnit.h:922
TAllRoutes::Route2MultiMapInsert
void Route2MultiMapInsert(int Caller, int HLoc, int VLoc, int ELinkIn, int RouteNumber, unsigned int RouteElementNumber)
Insert an entry in Route2MultiMap. Called by TAllRoutes::AddRouteElement.
Definition: TrackUnit.cpp:18244
TFixedTrackPiece::GraphicPtr
Graphics::TBitmap * GraphicPtr
the track bitmap for display on the zoomed-in railway
Definition: TrackUnit.h:91
TRailGraphics::sm2
Graphics::TBitmap * sm2
Definition: GraphicUnit.h:805
clB5G0R0
#define clB5G0R0
Definition: GraphicUnit.h:246
TRailGraphics::sm73
Graphics::TBitmap * sm73
Definition: GraphicUnit.h:923
TTrack::IsNamedNonStationLocationPresent
bool IsNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location at HLoc & VLoc.
Definition: TrackUnit.cpp:9980
TRailGraphics::sm21
Graphics::TBitmap * sm21
Definition: GraphicUnit.h:807
TAllRoutes::SetAllRearwardsSignals
void SetAllRearwardsSignals(int Caller, int Attribute, int RouteNumber, int RouteStartPosition)
Set rearwards signals from the specified route starting position.
Definition: TrackUnit.cpp:18654
TRailGraphics::sm123
Graphics::TBitmap * sm123
Definition: GraphicUnit.h:934
TOnePrefDir::SearchLimitLowV
int SearchLimitLowV
Definition: TrackUnit.h:1338
TRailGraphics::bm8
Graphics::TBitmap * bm8
Definition: GraphicUnit.h:509
TTrack::GapMap
TGapMap GapMap
map of gaps (see type for more information above)
Definition: TrackUnit.h:782
TRailGraphics::gl117
Graphics::TBitmap * gl117
Definition: GraphicUnit.h:595
TRailGraphics::gl89set
Graphics::TBitmap * gl89set
Definition: GraphicUnit.h:716
TOnePrefDir::ErasePrefDirElementAt
void ErasePrefDirElementAt(int Caller, int PrefDirVectorPosition)
Erase a single element from PrefDirVector and 4MultiMap, decrementing the remaining PrefDirElementNum...
Definition: TrackUnit.cpp:13359
TRailGraphics::sm104
Graphics::TBitmap * sm104
Definition: GraphicUnit.h:773
TRailGraphics::gl19
Graphics::TBitmap * gl19
Definition: GraphicUnit.h:634
TTrack::UserGraphicMap
TUserGraphicMap UserGraphicMap
the map of graphic filenames as key and TPicture* as values
Definition: TrackUnit.h:797
TGraphicElement::ScreenSourceSet
bool ScreenSourceSet
Definition: TrackUnit.h:430
TOnePrefDir::CheckPrefDirAgainstTrackVector
void CheckPrefDirAgainstTrackVector(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefD...
Definition: TrackUnit.cpp:12978
TRailGraphics::gl72
Graphics::TBitmap * gl72
Definition: GraphicUnit.h:693
TRailGraphics::ChangeAllTransparentColours
void ChangeAllTransparentColours(TColor NewTransparentColour, TColor OldTransparentColour)
Definition: GraphicUnit.cpp:3686
TRailGraphics::gl88set
Graphics::TBitmap * gl88set
Definition: GraphicUnit.h:714
TRailGraphics::bm28
Graphics::TBitmap * bm28
Definition: GraphicUnit.h:395
TRailGraphics::bm68grounddblred
Graphics::TBitmap * bm68grounddblred
Definition: GraphicUnit.h:454
TRailGraphics::smLC
Graphics::TBitmap * smLC
Definition: GraphicUnit.h:895
TTrack::BarriersDownVector
TActiveLCVector BarriersDownVector
vector of LCs with barriers down
Definition: TrackUnit.h:780
TPrefDirElement::GetXLinkPos
int GetXLinkPos() const
Returns the XLink array position.
Definition: TrackUnit.h:281
TTrack::IsLCBarrierDownAtHV
bool IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc)
True if an open (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:7235
TAllRoutes::TLockedRouteClass::TruncateTrackVectorPosition
unsigned int TruncateTrackVectorPosition
the TrackVector position of the element selected for truncation
Definition: TrackUnit.h:1607
TOneRoute::GetRouteTruncateElement
void GetRouteTruncateElement(int Caller, int HLoc, int VLoc, bool PrefDirRoute, TTruncateReturnType &ReturnFlag)
Examines the route to see whether the element at H & V is in the route, and if not returns a ReturnFl...
Definition: TrackUnit.cpp:17160
TRailGraphics::bm70grounddblred
Graphics::TBitmap * bm70grounddblred
Definition: GraphicUnit.h:467
TUtilities::ScreenElementWidth
int ScreenElementWidth
width of display screen in elements
Definition: Utilities.h:48
TRailGraphics::gl75
Graphics::TBitmap * gl75
Definition: GraphicUnit.h:698
TAllRoutes::LockedRouteLockStartTime
TDateTime LockedRouteLockStartTime
Definition: TrackUnit.h:1670
TTrack::TSigElement::Attribute
int Attribute
the signal state - red, yellow, double yellow or green
Definition: TrackUnit.h:711
TTrack::GetVectorPositionFromTrackMap
int GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Returns the track vector position corresponding to the Hloc & VLoc positions, FoundFlag indicates whe...
Definition: TrackUnit.cpp:5687
TTrack::PlotLCBaseElementsOnly
void PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp)
Just replot the basic track elements at a level crossing (for flashing)
Definition: TrackUnit.cpp:7136
TTrack::GetTrackElementFromTrackMap
TTrackElement & GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5714
TOneRoute::TRouteFlash::OverlayPlotted
bool OverlayPlotted
flag indicating the graphic that is currently displayed, true for the overlay (route-coloured)
Definition: TrackUnit.h:1492
TTrack::LeftPlatAllowed
Set< int, 1, 146 > LeftPlatAllowed
Definition: TrackUnit.h:586
TAllRoutes::TRouteElementPair
std::pair< int, unsigned int > TRouteElementPair
defines a specific element in a route, the first (int) value is the vector position in the AllRoutesV...
Definition: TrackUnit.h:1631
NamedNonStationLocation
@ NamedNonStationLocation
Definition: TrackUnit.h:66
TRailGraphics::sm51
Graphics::TBitmap * sm51
Definition: GraphicUnit.h:840
TRailGraphics::sm77
Graphics::TBitmap * sm77
Definition: GraphicUnit.h:861
TTrack::NoActiveTrack
bool NoActiveTrack(int Caller)
True if there is no active track in the railway.
Definition: TrackUnit.cpp:1928
TPrefDirElement::GetRouteAutoSigsGraphicPtr
Graphics::TBitmap * GetRouteAutoSigsGraphicPtr()
picks up the blue route graphic (not used - superseded by GetRouteGraphicPtr)
Definition: TrackUnit.cpp:934
TTrack::CalcHLocMinEtc
void CalcHLocMinEtc(int Caller)
Examine TrackVector, InactiveTrackVector and TextVector, and set the values that indicate the extent ...
Definition: TrackUnit.cpp:10314
TTrack::TActiveLevelCrossing::ReducedTimePenalty
bool ReducedTimePenalty
marker that is set when a train is present on one of the elements of the LC - used to provide a 3 min...
Definition: TrackUnit.h:616
TOneRoute::FindForwardTargetSignalAttribute
bool FindForwardTargetSignalAttribute(int Caller, int &NextForwardLinkedRouteNumber, int &Attribute) const
Used when setting signal aspects for a route by working forwards through the route to see what the ne...
Definition: TrackUnit.cpp:16910
TRailGraphics::gl143
Graphics::TBitmap * gl143
Definition: GraphicUnit.h:626
TRailGraphics::sm70
Graphics::TBitmap * sm70
Definition: GraphicUnit.h:920
TAllRoutes::DiagonalFouledByRoute
bool DiagonalFouledByRoute(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
As above but only checks for a route (may or may not be a train present (new at v1....
Definition: TrackUnit.cpp:19403
TGraphicElement::VPos
int VPos
horizontal and vertical positions
Definition: TrackUnit.h:432
TAllRoutes::LockedRouteFoundDuringRouteBuilding
bool LockedRouteFoundDuringRouteBuilding
this flags the fact that a locked route has been found during route building in an existing linked ro...
Definition: TrackUnit.h:1661
TTextHandler::TextVector
TTextVector TextVector
Definition: TextUnit.h:69
TTrack::Lowering
@ Lowering
Definition: TrackUnit.h:607
TTrack::FindNonPlatformMatch
bool FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement)
True if find a non-platform element at HLoc & VLoc, and if so return its TrackVector position and a r...
Definition: TrackUnit.cpp:2824
TRailGraphics::bm73CallingOn
Graphics::TBitmap * bm73CallingOn
Definition: GraphicUnit.h:484
TTrack::TFixedTrackArray::FixedTrackPiece
TFixedTrackPiece FixedTrackPiece[FirstUnusedSpeedTagNumber]
the array member
Definition: TrackUnit.h:551
TTrack::MatchingPoint
bool MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition)
Definition: TrackUnit.cpp:5867
TRailGraphics::LCBotHorMan
Graphics::TBitmap * LCBotHorMan
Definition: GraphicUnit.h:742
TRailGraphics::gl66
Graphics::TBitmap * gl66
Definition: GraphicUnit.h:686
TRailGraphics::bm69grounddblred
Graphics::TBitmap * bm69grounddblred
Definition: GraphicUnit.h:460
TTrackElement::StationEntryStopLinkPos2
int StationEntryStopLinkPos2
Used for track at platforms and non-station named locations to mark the train front element stop posi...
Definition: TrackUnit.h:150
TTrack::EnterLocationName
void EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
All platform, concourse, footcrossing & non-station named location elements are able to have a Locati...
Definition: TrackUnit.cpp:8154
TOneRoute::RouteSearchLimit
static const int RouteSearchLimit
limit to the number of elements searched in attempting to find a route
Definition: TrackUnit.h:1502
TUtilities::CheckFileStringZeroDelimiter
bool CheckFileStringZeroDelimiter(std::ifstream &InFile)
checks that the value is a string ('0' only accepted as the delimiter), returns true for success
Definition: Utilities.cpp:435
TTrack::TTrackVectorIterator
std::vector< TTrackElement >::iterator TTrackVectorIterator
iterator for TTrackVector
Definition: TrackUnit.h:645
TAllRoutes::ClearRouteDuringRouteBuildingAt
void ClearRouteDuringRouteBuildingAt(int Caller, int RouteNumber)
When attaching a new route section to an existing route, it is sometimes necessary to erase the origi...
Definition: TrackUnit.cpp:18082
TRailGraphics::sm108
Graphics::TBitmap * sm108
Definition: GraphicUnit.h:777
TTrack::Tag79Array
int Tag79Array[25][3]
Definition: TrackUnit.h:578
TRailGraphics::gl60
Graphics::TBitmap * gl60
Definition: GraphicUnit.h:680
TOnePrefDir::SavePrefDirVector
void SavePrefDirVector(int Caller, std::ofstream &VecFile)
Save the preferred direction vector to a file.
Definition: TrackUnit.cpp:12717
TRailGraphics::bm132
Graphics::TBitmap * bm132
Definition: GraphicUnit.h:360
TTrack::GetTrackLocsFromScreenPos
void GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos except that in this function HLoc & VLoc are expressed in t...
Definition: TrackUnit.cpp:7621
TRailGraphics::bm73
Graphics::TBitmap * bm73
Definition: GraphicUnit.h:483
TRailGraphics::bm30
Graphics::TBitmap * bm30
Definition: GraphicUnit.h:401
TTrainController::TrainVectorAtIdent
TTrain & TrainVectorAtIdent(int Caller, int TrainID)
Return a reference to the train with ID TrainID, carries out validity checking on TrainID.
Definition: TrainUnit.cpp:9824
TTrack::DecrementValuesInGapsAndTrackAndNameMaps
void DecrementValuesInGapsAndTrackAndNameMaps(int Caller, unsigned int VecPos)
After an element has been erased from the TrackVector, all the later elements are moved down one....
Definition: TrackUnit.cpp:9358
TOnePrefDir::GetStartAndEndPrefDirElements
bool GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
Called when searching for start and end PrefDirElements when setting up automatic signals routes in P...
Definition: TrackUnit.cpp:14007
TTextItem::HPos
int HPos
the horizontal position on the railway
Definition: TextUnit.h:48
TTrainController::StopTTClockMessage
void StopTTClockMessage(int Caller, AnsiString Message)
sends a message to the user and stops the timetable clock while it is displayed
Definition: TrainUnit.cpp:15384
TRailGraphics::gl103
Graphics::TBitmap * gl103
Definition: GraphicUnit.h:580
TAllRoutes::GetAllRoutesTruncateElement
bool GetAllRoutesTruncateElement(int Caller, int HLoc, int VLoc, bool PrefDirRoute)
Examines all routes and for each uses GetRouteTruncateElement to see if the element at H & V is prese...
Definition: TrackUnit.cpp:17608
TAllRoutes::RemoveRouteElement
void RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
Erases the route element from Route2MultiMap and from the PrefDirVector.
Definition: TrackUnit.cpp:18444
TRailGraphics::sm83
Graphics::TBitmap * sm83
Definition: GraphicUnit.h:871
TTrack::NoPlatsMessageSent
bool NoPlatsMessageSent
used to send no platforms warning once only
Definition: TrackUnit.h:740
TRailGraphics::sm81
Graphics::TBitmap * sm81
Definition: GraphicUnit.h:869
TRailGraphics::bm74grounddblwhite
Graphics::TBitmap * bm74grounddblwhite
Definition: GraphicUnit.h:494
TAllRoutes::TLockedRouteClass::LastXLinkPos
int LastXLinkPos
the XLinkPos value of the last (i.e. most forward) element in the route
Definition: TrackUnit.h:1611
TRailGraphics::sm97
Graphics::TBitmap * sm97
Definition: GraphicUnit.h:887
TRailGraphics::Concourse
Graphics::TBitmap * Concourse
Definition: GraphicUnit.h:548
TOnePrefDir::LoadOldPrefDir
void LoadOldPrefDir(int Caller, std::ifstream &VecFile)
Old version of LoadPrefDir, used during development when the save format changed so the old files cou...
Definition: TrackUnit.cpp:12521
TTrackElement::FourAspect
@ FourAspect
Definition: TrackUnit.h:157
TRailGraphics::bm9
Graphics::TBitmap * bm9
Definition: GraphicUnit.h:513
TTrack::FindSetAndDisplayMatchingGap
bool FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc)
True if find an unset gap that matches the gap at HLoc & VLoc, if find one mark it with a green circl...
Definition: TrackUnit.cpp:4455
TTrack::CheckActiveLCVector
bool CheckActiveLCVector(int Caller, std::ifstream &VecFile)
Definition: TrackUnit.cpp:3662
TRailGraphics::gl67
Graphics::TBitmap * gl67
Definition: GraphicUnit.h:687
TRailGraphics::sm56
Graphics::TBitmap * sm56
Definition: GraphicUnit.h:845
TOneRoute::StartRoutePosition
int StartRoutePosition
TrackVectorPosition of the StartElement(s) set when the starting position of a new route is selected,...
Definition: TrackUnit.h:1514
TRailGraphics::bm69dblyellow
Graphics::TBitmap * bm69dblyellow
Definition: GraphicUnit.h:459
TRailGraphics::gl118
Graphics::TBitmap * gl118
Definition: GraphicUnit.h:596
TRailGraphics::sm105
Graphics::TBitmap * sm105
Definition: GraphicUnit.h:774
TRailGraphics::bm70dblyellow
Graphics::TBitmap * bm70dblyellow
Definition: GraphicUnit.h:466
TRailGraphics::sm24
Graphics::TBitmap * sm24
Definition: GraphicUnit.h:810
TTrack::CheckFootCrossingLinks
bool CheckFootCrossingLinks(int Caller, TTrackElement &TrackElement)
True if a footcrossing is linked properly at both ends.
Definition: TrackUnit.cpp:7969
TGraphicElement::SourceRect
TRect SourceRect
source rectangle of the original graphic
Definition: TrackUnit.h:438
TUtilities::LoadFileDouble
double LoadFileDouble(std::ifstream &InFile)
loads a double value from the file (converts from a string to a double) and uses the local decimal po...
Definition: Utilities.cpp:172
TRailGraphics::gl57
Graphics::TBitmap * gl57
Definition: GraphicUnit.h:676
TRailGraphics::gl120
Graphics::TBitmap * gl120
Definition: GraphicUnit.h:599
TPrefDirElement::GetDirectionRouteGraphicPtr
Graphics::TBitmap * GetDirectionRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute) const
picks up the green or red route direction graphic
Definition: TrackUnit.cpp:1046
TTrack::ShowSelectedGap
void ShowSelectedGap(int Caller, TDisplay *Disp)
Called during gap setting to mark a gap with a red circle - after which the program awaits user selec...
Definition: TrackUnit.cpp:4615
TOnePrefDir::TPrefDir4MultiMapEntry
std::pair< THVPair, unsigned int > TPrefDir4MultiMapEntry
Definition: TrackUnit.h:1298
TTrack::PlotLoweredLinkedLevelCrossingBarriers
void PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp, bool Manual)
Plot & open (to trains) all level crossings linked to TrackElement (Manual true = manually lowered,...
Definition: TrackUnit.cpp:6419
TTrack::OneNamedLocationElementAtLocation
bool OneNamedLocationElementAtLocation(int Caller, AnsiString LocationName)
True if there is at least one named location element with name 'LocationName', used in timetable inte...
Definition: TrackUnit.cpp:10803
TRailGraphics::gl5
Graphics::TBitmap * gl5
Definition: GraphicUnit.h:668
TRailGraphics::bm94unset
Graphics::TBitmap * bm94unset
Definition: GraphicUnit.h:517
TRailGraphics::sm93
Graphics::TBitmap * sm93
Definition: GraphicUnit.h:882
TTrack::CheckUserGraphics
bool CheckUserGraphics(int Caller, std::ifstream &InFile, UnicodeString GraphicsPath)
checks all user graphics & returns true for success
Definition: TrackUnit.cpp:3538
Unused
@ Unused
Definition: TrackUnit.h:65
TRailGraphics::gl122
Graphics::TBitmap * gl122
Definition: GraphicUnit.h:601
TRailGraphics::gl15
Graphics::TBitmap * gl15
Definition: GraphicUnit.h:631
TTrackElement::SigAspect
enum TTrackElement::@1 SigAspect
TOnePrefDir::TPrefDir4MultiMapIterator
std::multimap< THVPair, unsigned int, TMapComp >::iterator TPrefDir4MultiMapIterator
Definition: TrackUnit.h:1297
TRailGraphics::bm74
Graphics::TBitmap * bm74
Definition: GraphicUnit.h:490
TRailGraphics::gl90set
Graphics::TBitmap * gl90set
Definition: GraphicUnit.h:719
TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber
bool IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos, TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
Checks whether the preferred direction element at TrackVectorPosition with XLinkPos value is in a loc...
Definition: TrackUnit.cpp:18918
TrackUnit.h
TTrack::ReturnNextInactiveTrackElement
bool ReturnNextInactiveTrackElement(int Caller, TTrackElement &Next)
Return a reference to the inactive track element pointed to by NextTrackElementPtr (during zoomed-in ...
Definition: TrackUnit.cpp:2857
TRailGraphics::sm117
Graphics::TBitmap * sm117
Definition: GraphicUnit.h:784
TPrefDirElement::IsARoute
bool IsARoute
false for Pref Dir, true for route
Definition: TrackUnit.h:222
TAllRoutes::CheckRoutes
bool CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
Performs an integrity check on the routes stored in a session file and returns false if there is an e...
Definition: TrackUnit.cpp:19113
TTrack::Tag76Array
int Tag76Array[25][3]
these arrays give valid adjacent named element relative positions for each type of named element,...
Definition: TrackUnit.h:574
TTrack::LengthMarker
void LengthMarker(int Caller, TDisplay *Disp)
Examine all elements in the TrackVector and if have a valid length mark the relevant track using Mark...
Definition: TrackUnit.cpp:9525
TAllRoutes::LockedRouteLastTrackVectorPosition
unsigned int LockedRouteLastTrackVectorPosition
Definition: TrackUnit.h:1669
TOneRoute::RouteID
int RouteID
the ID number of the route, this is needed for session saves
Definition: TrackUnit.h:1512
TAllRoutes
Handles data and functions relating to all routes on the railway.
Definition: TrackUnit.h:1598
TPrefDirElement::TrackVectorPosition
int TrackVectorPosition
TrackVectorPosition of the corresponding track element.
Definition: TrackUnit.h:204
TRailGraphics::sm121
Graphics::TBitmap * sm121
Definition: GraphicUnit.h:932
TUserGraphicItem::VPos
int VPos
Definition: DisplayUnit.h:34
Utilities.h
TTrainController::TContinuationAutoSigVectorIterator
TContinuationAutoSigVector::iterator TContinuationAutoSigVectorIterator
Definition: TrainUnit.h:723
TGraphicElement::OriginalGraphic
Graphics::TBitmap * OriginalGraphic
Definition: TrackUnit.h:436
TRailGraphics::sm46
Graphics::TBitmap * sm46
Definition: GraphicUnit.h:834
TTrack::SaveTrack
void SaveTrack(int Caller, std::ofstream &VecFile, bool GraphicsFollow)
Save all active and inactive track elements to VecFile.
Definition: TrackUnit.cpp:3262
TOneRoute::GetNonPreferredRouteStartElement
bool GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool Callon)
Set the starting conditions for a non-preferred (i.e. unrestricted) route selection beginning on HLoc...
Definition: TrackUnit.cpp:15593
TUserGraphicItem::HPos
int HPos
Definition: DisplayUnit.h:34
TDisplay::Update
void Update()
Repaint the screen display.
Definition: DisplayUnit.h:222
TRailGraphics::sm131striped
Graphics::TBitmap * sm131striped
Definition: GraphicUnit.h:791
TRailGraphics::gl63
Graphics::TBitmap * gl63
Definition: GraphicUnit.h:683
TRailGraphics::bm75grounddblwhite
Graphics::TBitmap * bm75grounddblwhite
Definition: GraphicUnit.h:500
TTrack::AdjElement
bool AdjElement(int Caller, int HLoc, int VLoc, int SpeedTag, int &FoundElement)
Used during location naming to check for adjacent named elements to a given element at HLoc & VLoc wi...
Definition: TrackUnit.cpp:8421
TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap
void EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails ...
Definition: TrackUnit.cpp:12783
Simple
@ Simple
Definition: TrackUnit.h:65
TTrack::GapFlashGreen
TGraphicElement * GapFlashGreen
Definition: TrackUnit.h:784
TRailGraphics::bm46
Graphics::TBitmap * bm46
Definition: GraphicUnit.h:444
TUtilities::RHSignalFlag
bool RHSignalFlag
new at v2.3.0 false=LH signals
Definition: Utilities.h:40
TRailGraphics::bm72dblyellow
Graphics::TBitmap * bm72dblyellow
Definition: GraphicUnit.h:478
TRailGraphics::sm22
Graphics::TBitmap * sm22
Definition: GraphicUnit.h:808
TTrack::NumberOfGaps
int NumberOfGaps(int Caller)
Returns the number of gaps in the railway.
Definition: TrackUnit.cpp:2873
TTrack::TSigElement::SigPtr
Graphics::TBitmap * SigPtr
pointer to the graphic
Definition: TrackUnit.h:713
TRailGraphics::BridgeNonSigRouteGraphicsPtr
Graphics::TBitmap * BridgeNonSigRouteGraphicsPtr[12]
route graphic for unrestricted route overlay
Definition: GraphicUnit.h:1020
TAllRoutes::FindRouteNumberFromRoute2MultiMapNoErrors
bool FindRouteNumberFromRoute2MultiMapNoErrors(int Caller, int HLoc, int VLoc, int ELink, int &RouteNumber)
If a route is present at H, V & Elink returns true with RouteNumber giving vector position in AllRout...
Definition: TrackUnit.cpp:18192
TRailGraphics::sm130
Graphics::TBitmap * sm130
Definition: GraphicUnit.h:789
TRailGraphics::sm45
Graphics::TBitmap * sm45
Definition: GraphicUnit.h:833
TRailGraphics::bm38
Graphics::TBitmap * bm38
Definition: GraphicUnit.h:425
TOnePrefDir::TPrefDirVectorIterator
std::vector< TPrefDirElement >::iterator TPrefDirVectorIterator
Definition: TrackUnit.h:1365
TRailGraphics::gl90unset
Graphics::TBitmap * gl90unset
Definition: GraphicUnit.h:720
TOnePrefDir::CheckPrefDirAgainstTrackVectorNoMessage
bool CheckPrefDirAgainstTrackVectorNoMessage(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4Mu...
Definition: TrackUnit.cpp:13034
TTrack::WriteTrackAndTextToImage
void WriteTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveImageNoGrid1Click, TInterface::SaveImageAndGrid1Click and TInterface::SaveI...
Definition: TrackUnit.cpp:3859
TGraphicElement::TGraphicElement
TGraphicElement()
Default constructor (16 x 16 pixel element)
Definition: TrackUnit.cpp:1734
TRailGraphics::gl129Striped
Graphics::TBitmap * gl129Striped
Definition: GraphicUnit.h:609
TTrack::GetVectorPositionsFromInactiveTrackMap
TIMPair GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Similar to GetVectorPositionFromTrackMap but for inactive elements, a pair is returned because there ...
Definition: TrackUnit.cpp:5827
TRailGraphics::gl64
Graphics::TBitmap * gl64
Definition: GraphicUnit.h:684
TTrain
Definition: TrainUnit.h:304
TPrefDirElement::TPrefDirElement
TPrefDirElement()
Default constructor, loads default values.
Definition: TrackUnit.h:376
TOnePrefDir::PresetAutoRouteDiagonalFouledByTrack
bool PresetAutoRouteDiagonalFouledByTrack(int Caller, TPrefDirElement ElementIn, int XLink)
Called by GetStartAndEndPrefDirElements...
Definition: TrackUnit.cpp:13878
TRailGraphics::bm77Striped
Graphics::TBitmap * bm77Striped
Definition: GraphicUnit.h:504
TFixedTrackPiece::TFixedTrackPiece
TFixedTrackPiece()
Default constructor.
Definition: TrackUnit.cpp:116
TTrackElement::TrainIDOnBridgeTrackPos23
int TrainIDOnBridgeTrackPos23
Set to the TrainID value when a train is present on the element, bridges can have two trains present ...
Definition: TrackUnit.h:152
TOnePrefDir::GetFixedPrefDirElementAt
const TPrefDirElement & GetFixedPrefDirElementAt(int Caller, int At) const
Return a non-modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:11433
TRailGraphics::bm74grounddblred
Graphics::TBitmap * bm74grounddblred
Definition: GraphicUnit.h:493
TRailGraphics::gl1
Graphics::TBitmap * gl1
Definition: GraphicUnit.h:575
TTrack::LinkCheckArray
int LinkCheckArray[9][2]
array of valid link connecting values, I don't think this is used now
Definition: TrackUnit.h:570
TRailGraphics::sm66
Graphics::TBitmap * sm66
Definition: GraphicUnit.h:856
TTrack::TActiveLevelCrossing::VLoc
int VLoc
VLoc value for found level crossing element.
Definition: TrackUnit.h:626
TTrack::GetTruePositionsFromScreenPos
void GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos.
Definition: TrackUnit.cpp:7636
TRailGraphics::bm35
Graphics::TBitmap * bm35
Definition: GraphicUnit.h:416
TRailGraphics::bm10
Graphics::TBitmap * bm10
Definition: GraphicUnit.h:347
GapJump
@ GapJump
Definition: TrackUnit.h:65
TRailGraphics::bm45
Graphics::TBitmap * bm45
Definition: GraphicUnit.h:443
TRailGraphics::sm19
Graphics::TBitmap * sm19
Definition: GraphicUnit.h:804
TAllRoutes::AddRouteElement
void AddRouteElement(int Caller, int HLoc, int VLoc, int ELink, int RouteNumber, TPrefDirElement RouteElement)
A single TPrefDirElement is added to both PrefDirVector (for the route at RouteNumber) and Route2Mult...
Definition: TrackUnit.cpp:18553
TRailGraphics::sm82
Graphics::TBitmap * sm82
Definition: GraphicUnit.h:870
TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains
bool AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector, bool &TrainPresent)
True if a route or train present on any linked level crossing element.
Definition: TrackUnit.cpp:7382
TTrackElement::Length01
int Length01
Definition: TrackUnit.h:148
TRailGraphics::bm71dblyellow
Graphics::TBitmap * bm71dblyellow
Definition: GraphicUnit.h:472
TRailGraphics::sm124
Graphics::TBitmap * sm124
Definition: GraphicUnit.h:935
TRailGraphics::bm69CallingOn
Graphics::TBitmap * bm69CallingOn
Definition: GraphicUnit.h:458
TTrackElement::SpeedLimit01
int SpeedLimit01
Definition: TrackUnit.h:148
TTrack::Raising
@ Raising
Definition: TrackUnit.h:607
TRailGraphics::gl26
Graphics::TBitmap * gl26
Definition: GraphicUnit.h:642
TTrack::VLocMax
int VLocMax
give extent of railway for use in zoomed in and out displays and in saving railway images
Definition: TrackUnit.h:568
TTrack::UserGraphicMove
void UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos, bool &UserGraphicFoundFlag)
handles moving of user graphics
Definition: TrackUnit.cpp:10419
TTextHandler::FindText
bool FindText(int Caller, AnsiString Name, int &HPos, int &VPos)
look in TextVector for text item 'Name', and if found return true and return its position in &HPos an...
Definition: TextUnit.cpp:585
TDisplay::DisplayOffsetV
static int DisplayOffsetV
the vertical offset of the displayed screen
Definition: DisplayUnit.h:79
TOneRoute::StartElement2
TPrefDirElement StartElement2
the two preferred direction elements corresponding to the starting position of a new route
Definition: TrackUnit.h:1516
TOneRoute::TRouteFlashElement::VLoc
int VLoc
Definition: TrackUnit.h:1480
TRailGraphics::gl86
Graphics::TBitmap * gl86
Definition: GraphicUnit.h:712
TRailGraphics::bm134
Graphics::TBitmap * bm134
Definition: GraphicUnit.h:366
TTrainController::BaseTime
TDateTime BaseTime
CurrentDateTime (i.e. real time) when operation restarts after a pause.
Definition: TrainUnit.h:696
TTrack::Tag129Array
int Tag129Array[8][3]
Definition: TrackUnit.h:580
TTrack::InactiveTrack2MultiMap
TInactiveTrack2MultiMap InactiveTrack2MultiMap
multimap of inactive TrackElements (see type for more information above)
Definition: TrackUnit.h:786
TRailGraphics::bm14
Graphics::TBitmap * bm14
Definition: GraphicUnit.h:386
TRailGraphics::sm106
Graphics::TBitmap * sm106
Definition: GraphicUnit.h:775
TRailGraphics::bm68dblyellow
Graphics::TBitmap * bm68dblyellow
Definition: GraphicUnit.h:453
TRailGraphics::gl97
Graphics::TBitmap * gl97
Definition: GraphicUnit.h:729
TOnePrefDir::PrefDirSize
unsigned int PrefDirSize() const
Return the vector size.
Definition: TrackUnit.h:1374
TTrack::PlotSignal
void PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plot signals on screen according to their aspect (Attribute value)
Definition: TrackUnit.cpp:6079
End
@ End
Definition: TrackUnit.h:75
TUserGraphicItem
Definition: DisplayUnit.h:31
TOneRoute::RouteFlash
TRouteFlash RouteFlash
the class member that allows the route to flash during setting up (see TRouteFlash above)
Definition: TrackUnit.h:1518
TRailGraphics::gl62
Graphics::TBitmap * gl62
Definition: GraphicUnit.h:682
TRailGraphics::sm67
Graphics::TBitmap * sm67
Definition: GraphicUnit.h:857
TTrack::TActiveLevelCrossing::BarrierState
TBarrierState BarrierState
state of barriers - Raising, Lowering, Up, Down (an enum - see above)
Definition: TrackUnit.h:618
TTrack::TimetabledLocationNameAllocated
bool TimetabledLocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found as a timetabled location name i.e. not as a continuation name.
Definition: TrackUnit.cpp:8775
TRailGraphics::sm9
Graphics::TBitmap * sm9
Definition: GraphicUnit.h:878
TRailGraphics::sm68
Graphics::TBitmap * sm68
Definition: GraphicUnit.h:918
clB0G0R5
#define clB0G0R5
Definition: GraphicUnit.h:41
TTrack::TrackFinished
bool TrackFinished
marker for all Conn & ConnLinkPos values set & track complete
Definition: TrackUnit.h:563
TTrack::InactiveTrackElementAt
TTrackElement & InactiveTrackElementAt(int Caller, int At)
A range-checked version of InactiveTrackVector.at(At)
Definition: TrackUnit.cpp:10528
TRailGraphics::LinkNonSigRouteGraphicsPtr
Graphics::TBitmap * LinkNonSigRouteGraphicsPtr[30]
unrestricted route graphic overlay
Definition: GraphicUnit.h:1033
TPrefDirElement::GetTrackVectorPosition
unsigned int GetTrackVectorPosition() const
Returns TrackVectorPosition.
Definition: TrackUnit.h:299
TRailGraphics::sm28
Graphics::TBitmap * sm28
Definition: GraphicUnit.h:814
TTrack::RouteFailMessage
AnsiString RouteFailMessage
Definition: TrackUnit.h:726
clB0G5R0
#define clB0G5R0
Definition: GraphicUnit.h:71
TTrack::LNPendingList
TLNPendingList LNPendingList
list of location name elements awaiting processing (see type for more information above)
Definition: TrackUnit.h:792
TRailGraphics::gl114
Graphics::TBitmap * gl114
Definition: GraphicUnit.h:592
TRailGraphics::sm116
Graphics::TBitmap * sm116
Definition: GraphicUnit.h:928
TTrackElement
Basic track elements as implemented in the overall railway layout.
Definition: TrackUnit.h:124
TRailGraphics::LCLHSVer
Graphics::TBitmap * LCLHSVer
Definition: GraphicUnit.h:737
TRailGraphics::bm74dblyellow
Graphics::TBitmap * bm74dblyellow
Definition: GraphicUnit.h:492
TRailGraphics::sm103
Graphics::TBitmap * sm103
Definition: GraphicUnit.h:772
TTrack::RebuildUserGraphics
void RebuildUserGraphics(int Caller, TDisplay *Disp)
rebuild user graphics
Definition: TrackUnit.cpp:3833
TRailGraphics::bmSolidBgnd
Graphics::TBitmap * bmSolidBgnd
Definition: GraphicUnit.h:1004
TTrack::GroundSignalBuild
@ GroundSignalBuild
Definition: TrackUnit.h:848
TRailGraphics::smSolidBgnd
Graphics::TBitmap * smSolidBgnd
Definition: GraphicUnit.h:1005
TPrefDirElement::PrefDirRoute
bool PrefDirRoute
marker within the route for preferred direction route element
Definition: TrackUnit.h:226
TTextHandler::WriteTextToImage
void WriteTextToImage(int Caller, Graphics::TBitmap *Bitmap)
write all items in TextVector to the railway image in 'Bitmap'
Definition: TextUnit.cpp:442
TRailGraphics::bmNameStriped
Graphics::TBitmap * bmNameStriped
Definition: GraphicUnit.h:525
TRailGraphics::gl88unset
Graphics::TBitmap * gl88unset
Definition: GraphicUnit.h:715
SignalPost
@ SignalPost
Definition: TrackUnit.h:65
TTrack::SetAllDefaultLengthsAndSpeedLimits
void SetAllDefaultLengthsAndSpeedLimits(int Caller)
Work through all elements in TrackVector setting all lengths & speed limits to default values - inclu...
Definition: TrackUnit.cpp:9490
TRailGraphics::BridgeGraphicsPtr
Graphics::TBitmap * BridgeGraphicsPtr[12]
basic graphic for use in plotting the original graphic during route flashing
Definition: GraphicUnit.h:1014
TRailGraphics::bm69green
Graphics::TBitmap * bm69green
Definition: GraphicUnit.h:462
TAllRoutes::WriteAllRoutesToImage
void WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
Calls RouteImageMarker for each route in turn to display the route colours and direction arrows on th...
Definition: TrackUnit.cpp:17596
IDInt::GetInt
int GetInt() const
get the internal integer
Definition: TrackUnit.h:502
TRailGraphics::sm132
Graphics::TBitmap * sm132
Definition: GraphicUnit.h:792
TPrefDirElement::operator!=
bool operator!=(TPrefDirElement RHElement)
non-equivalence operator
Definition: TrackUnit.cpp:1091
TAllRoutes::TRoute2MultiMapIterator
TRoute2MultiMap::iterator TRoute2MultiMapIterator
Definition: TrackUnit.h:1635
TRailGraphics::sm20
Graphics::TBitmap * sm20
Definition: GraphicUnit.h:806
TRailGraphics::sm52
Graphics::TBitmap * sm52
Definition: GraphicUnit.h:841
TTrack::GetScreenPositionsFromTruePos
void GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
With large railways only part of the railway is displayed on screen, and this function converts true ...
Definition: TrackUnit.cpp:7650
TRailGraphics::bm68yellow
Graphics::TBitmap * bm68yellow
Definition: GraphicUnit.h:457
TTrack::TInactiveTrackRange
std::pair< TInactiveTrack2MultiMapIterator, TInactiveTrack2MultiMapIterator > TInactiveTrackRange
range for TInactiveTrack2MultiMap
Definition: TrackUnit.h:667
TRailGraphics::bm31
Graphics::TBitmap * bm31
Definition: GraphicUnit.h:404
TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp, bool Manual)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway (...
Definition: TrackUnit.cpp:6828
TTrack::TTrackVector
std::vector< TTrackElement > TTrackVector
vector of TrackElements
Definition: TrackUnit.h:643
TPrefDirElement::AutoSignals
bool AutoSignals
marker within the route for an AutoSignal route element
Definition: TrackUnit.h:224
TRailGraphics::bm74CallingOn
Graphics::TBitmap * bm74CallingOn
Definition: GraphicUnit.h:491
TRailGraphics::gl76
Graphics::TBitmap * gl76
Definition: GraphicUnit.h:699
FirstUnusedSpeedTagNumber
#define FirstUnusedSpeedTagNumber
Definition: TrackUnit.h:36
TTrack::EraseLocationAndActiveTrackElementNames
void EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both ac...
Definition: TrackUnit.cpp:8814
TRailGraphics::sm71
Graphics::TBitmap * sm71
Definition: GraphicUnit.h:921
TRailGraphics::sm43
Graphics::TBitmap * sm43
Definition: GraphicUnit.h:831
TAllRoutes::MarkAllRoutes
void MarkAllRoutes(int Caller, TDisplay *Disp)
Calls PrefDirMarker for all routes, with RouteCall set to identify a route call, and BuildingPrefDir ...
Definition: TrackUnit.cpp:17581
TRailGraphics::sm101
Graphics::TBitmap * sm101
Definition: GraphicUnit.h:770
Concourse
@ Concourse
Definition: TrackUnit.h:66
TTrack::BotPlatAllowed
Set< int, 1, 146 > BotPlatAllowed
Definition: TrackUnit.h:586
TRailGraphics::gl52
Graphics::TBitmap * gl52
Definition: GraphicUnit.h:671
TTrack::SelectVector
TTrackVector SelectVector
vectors of TrackElements
Definition: TrackUnit.h:801
TRailGraphics::sm29
Graphics::TBitmap * sm29
Definition: GraphicUnit.h:815
TConfiguration
TConfiguration
< describes the type of track link. 'End' is used for both buffer stop and continuation entry/exit po...
Definition: TrackUnit.h:74
TOnePrefDir::WritePrefDirToImage
void WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
Used when creating a bitmap image to display preferred directions (as on screen during 'Set preferred...
Definition: TrackUnit.cpp:13648
TOnePrefDir::DecrementPrefDirElementNumbersInPrefDir4MultiMap
void DecrementPrefDirElementNumbersInPrefDir4MultiMap(int Caller, unsigned int ErasedElementNumber)
Called after ErasePrefDirElementAt to decrement the remaining PrefDirElementNumbers in 4MultiMap if t...
Definition: TrackUnit.cpp:13385
TTrackElement::LogTrack
AnsiString LogTrack(int Caller) const
Used to log track parameters for call stack logging.
Definition: TrackUnit.cpp:230
TRailGraphics::gl95unset
Graphics::TBitmap * gl95unset
Definition: GraphicUnit.h:728
TTrack::TrackVectorSize
int TrackVectorSize()
Return the number of active track elements.
Definition: TrackUnit.h:901
TTrackType
TTrackType
< describes the type of track element
Definition: TrackUnit.h:64
TRailGraphics::bm77
Graphics::TBitmap * bm77
Definition: GraphicUnit.h:503
TTrack::NoGaps
bool NoGaps(int Caller)
True if there are no gaps.
Definition: TrackUnit.cpp:4540
TGraphicElement::PlotOriginal
void PlotOriginal(int Caller, TDisplay *Disp)
Plot the original graphic on screen.
Definition: TrackUnit.cpp:1878
TextHandler
TTextHandler * TextHandler
Definition: TextUnit.cpp:95
TRailGraphics::bm39
Graphics::TBitmap * bm39
Definition: GraphicUnit.h:428
TRailGraphics::sm40
Graphics::TBitmap * sm40
Definition: GraphicUnit.h:828
TRailGraphics::bm41
Graphics::TBitmap * bm41
Definition: GraphicUnit.h:434
TRailGraphics::sm54
Graphics::TBitmap * sm54
Definition: GraphicUnit.h:843
TRailGraphics::bm72green
Graphics::TBitmap * bm72green
Definition: GraphicUnit.h:481
TRailGraphics::gl129
Graphics::TBitmap * gl129
Definition: GraphicUnit.h:608
TRailGraphics::sm31
Graphics::TBitmap * sm31
Definition: GraphicUnit.h:818
TGraphicElement::ExistingGraphicLoaded
bool ExistingGraphicLoaded
state flags
Definition: TrackUnit.h:430
TRailGraphics::bm74green
Graphics::TBitmap * bm74green
Definition: GraphicUnit.h:495
TUserGraphicItem::Width
int Width
Definition: DisplayUnit.h:35
TTrack::MirrorArray
int MirrorArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'mirroring' via menu items 'Edit' & 'Mirror'
Definition: TrackUnit.h:766
TRailGraphics::bm71grounddblred
Graphics::TBitmap * bm71grounddblred
Definition: GraphicUnit.h:473
Utilities
TUtilities * Utilities
Definition: Utilities.cpp:47
TFixedTrackPiece::SmallGraphicPtr
Graphics::TBitmap * SmallGraphicPtr
the track bitmap for display on the zoomed-out railway
Definition: TrackUnit.h:93
TRailGraphics::bm40
Graphics::TBitmap * bm40
Definition: GraphicUnit.h:431
TRailGraphics::sm42
Graphics::TBitmap * sm42
Definition: GraphicUnit.h:830
TRailGraphics::gl111
Graphics::TBitmap * gl111
Definition: GraphicUnit.h:589
TTrack::IsATrackElementAdjacentToLink
bool IsATrackElementAdjacentToLink(int Caller, int HLocIn, int VLocIn, int LinkIn)
True if there is an element adjacent to LinkIn for element at HLoc & VLoc.
Definition: TrackUnit.cpp:11006
TAllRoutes::DecrementRouteNumbersInRoute2MultiMap
void DecrementRouteNumbersInRoute2MultiMap(int Caller, int RouteNumber)
After a route has been erased from AllRoutesVector and its entries from Route2MultiMap,...
Definition: TrackUnit.cpp:18397
TTrack::BuildGapMapFromTrackVector
void BuildGapMapFromTrackVector(int Caller)
Examine TrackVector and whenever find a new gap pair enter it into GapMap.
Definition: TrackUnit.cpp:4774
TTrackElement::ThreeAspect
@ ThreeAspect
Definition: TrackUnit.h:157
TTrack::NoActiveOrInactiveTrack
bool NoActiveOrInactiveTrack(int Caller)
True if there is no active or inactive track in the railway.
Definition: TrackUnit.cpp:1897
TTrack::MultiplayerOverlayMap
TMultiplayerOverlayMap MultiplayerOverlayMap
Definition: TrackUnit.h:774
TRailGraphics::gl68
Graphics::TBitmap * gl68
Definition: GraphicUnit.h:688
TRailGraphics::sm18
Graphics::TBitmap * sm18
Definition: GraphicUnit.h:803
TRailGraphics::sm128
Graphics::TBitmap * sm128
Definition: GraphicUnit.h:939
TTrack::SuppressRouteFailMessage
bool SuppressRouteFailMessage
true if a message has been given in the search routine, to avoid giving multiple times and to avoid o...
Definition: TrackUnit.h:742
TTrack::FixedTrackArray
TFixedTrackArray FixedTrackArray
the FixedTrackPiece array object
Definition: TrackUnit.h:558
TDisplay::DisplayZoomOutOffsetVHome
static int DisplayZoomOutOffsetVHome
the vertical offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:91
TRailGraphics::gl121
Graphics::TBitmap * gl121
Definition: GraphicUnit.h:600
TRailGraphics::LCBothHor
Graphics::TBitmap * LCBothHor
Definition: GraphicUnit.h:734
TRailGraphics::sm6
Graphics::TBitmap * sm6
Definition: GraphicUnit.h:849
TPrefDirElement::GetOriginalGraphicPtr
Graphics::TBitmap * GetOriginalGraphicPtr()
picks up the original (non-flashing) graphic for use during route flashing
Definition: TrackUnit.cpp:464
TTrack::TTrackMap
std::map< THVPair, unsigned int, TMapComp > TTrackMap
map of TrackElement TrackVectorPositions, HLoc & VLoc pair is the key
Definition: TrackUnit.h:652
TTrack::DiagonalFouledByTrain
bool DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
As DiagonalFouledByRouteOrTrain (in TAllRoutes) but only checks for a train (may or may not be a rout...
Definition: TrackUnit.cpp:11251
TAllRoutes::IsThereARouteAtIDNumber
bool IsThereARouteAtIDNumber(int Caller, IDInt RouteID)
Returns true if there is a route with the given ID number - added at v1.3.1 (see function for details...
Definition: TrackUnit.cpp:19019
TTrack::NameAllowed
Set< int, 1, 146 > NameAllowed
Definition: TrackUnit.h:586
TRailGraphics::LinkSigRouteGraphicsPtr
Graphics::TBitmap * LinkSigRouteGraphicsPtr[30]
preferred direction route graphic overlay
Definition: GraphicUnit.h:1031
TRailGraphics::gl142
Graphics::TBitmap * gl142
Definition: GraphicUnit.h:625
TTrack::ReturnNextTrackElement
bool ReturnNextTrackElement(int Caller, TTrackElement &Next)
Return a reference to the active track element pointed to by NextTrackElementPtr (during zoomed-in or...
Definition: TrackUnit.cpp:2841
TRailGraphics::gl92unset
Graphics::TBitmap * gl92unset
Definition: GraphicUnit.h:724
TOneRoute::ClearRoute
void ClearRoute()
Empty the route of any stored elements.
Definition: TrackUnit.h:1524
TTrack::ResetAllTrainIDElements
void ResetAllTrainIDElements(int Caller)
Track elements have members that indicates whether and on what track a train is present (TrainIDOnEle...
Definition: TrackUnit.cpp:7607
TOneRoute::RouteImageMarker
void RouteImageMarker(int Caller, Graphics::TBitmap *Bitmap) const
Used when creating a bitmap image to display the route colours and direction arrows (as on screen dur...
Definition: TrackUnit.cpp:14824
TTrack::IsLCBarrierUpAtHV
bool IsLCBarrierUpAtHV(int Caller, int HLoc, int VLoc)
True if a closed (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:7263
TTrack::LocationNameAllocated
bool LocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found in LocationNameMultiMap.
Definition: TrackUnit.cpp:8611
TTrack::SetLCAttributeAtHV
void SetLCAttributeAtHV(int Caller, int HLoc, int VLoc, int Attr)
Set LC attribute at H & V; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to tra...
Definition: TrackUnit.cpp:7342
TRailGraphics::gl61
Graphics::TBitmap * gl61
Definition: GraphicUnit.h:681
TRailGraphics::LCBotHor
Graphics::TBitmap * LCBotHor
Definition: GraphicUnit.h:735
TTrack::GetTrackElementFromAnyTrackMap
TTrackElement & GetTrackElementFromAnyTrackMap(int Caller, int HLoc, int VLoc, TTrackMap &Map, TTrackVector &Vector)
Return a reference to the element at HLoc & VLoc for any map and any vector (used for SelectPrefDir i...
Definition: TrackUnit.cpp:5738
TTrack::TLocationNameMultiMapEntry
std::pair< AnsiString, int > TLocationNameMultiMapEntry
Definition: TrackUnit.h:689
TRailGraphics::gl55
Graphics::TBitmap * gl55
Definition: GraphicUnit.h:674
TUtilities::CallLogPop
void CallLogPop(int Caller)
pops the last entry off the call stack, throws an error if called when empty
Definition: Utilities.cpp:50
TTrain::MaximumSpeedLimit
static const int MaximumSpeedLimit
km/h
Definition: TrainUnit.h:317
TTrack::TLNDone2MultiMapIterator
TLNDone2MultiMap::iterator TLNDone2MultiMapIterator
during naming of linked named location elements, '2' because there
Definition: TrackUnit.h:680
TOnePrefDir::PrefDir4MultiMap
TPrefDir4MultiMap PrefDir4MultiMap
the pref dir multimap - up to 4 values (up to 2 tracks per element each with 2 directions)
Definition: TrackUnit.h:1300
TTrack::ThreeAspectBuild
@ ThreeAspectBuild
Definition: TrackUnit.h:848
TRailGraphics::sm30
Graphics::TBitmap * sm30
Definition: GraphicUnit.h:817
TRailGraphics::bm85
Graphics::TBitmap * bm85
Definition: GraphicUnit.h:510
TRailGraphics::sm3
Graphics::TBitmap * sm3
Definition: GraphicUnit.h:816
TRailGraphics::bm70yellow
Graphics::TBitmap * bm70yellow
Definition: GraphicUnit.h:470
TOnePrefDir::GetVectorPositionsFromPrefDir4MultiMap
void GetVectorPositionsFromPrefDir4MultiMap(int Caller, int HLoc, int VLoc, bool &FoundFlag, int &PrefDirPos0, int &PrefDirPos1, int &PrefDirPos2, int &PrefDirPos3)
Return up to 4 vector positions for a given HLoc & VLoc; unused values return -1.
Definition: TrackUnit.cpp:13122
TRailGraphics::sm110
Graphics::TBitmap * sm110
Definition: GraphicUnit.h:780
TRailGraphics::sm92
Graphics::TBitmap * sm92
Definition: GraphicUnit.h:881
TOnePrefDir::GetPrefDirTruncateElement
bool GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
Called during PrefDir build or distance setting. It truncates at & including the first element in the...
Definition: TrackUnit.cpp:12257
TAllRoutes::TRoute2MultiMapEntry
std::pair< THVPair, TRouteElementPair > TRoute2MultiMapEntry
Definition: TrackUnit.h:1636
TDisplay::PlotOutput
void PlotOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot the graphic at screen position HPos & VPos.
Definition: DisplayUnit.cpp:85
TAllRoutes::AllRoutesVector
TAllRoutesVector AllRoutesVector
the vector that stores all the routes on the railway
Definition: TrackUnit.h:1688
TUtilities::SaveFileBool
void SaveFileBool(std::ofstream &OutFile, bool SaveBool)
stores '1' if the bool is true or '0' if false to the file, then a CR
Definition: Utilities.cpp:108
TPrefDirVector
std::vector< TPrefDirElement > TPrefDirVector
forward declaration because needed in TTrack
Definition: TrackUnit.h:45
TRailGraphics::sm69
Graphics::TBitmap * sm69
Definition: GraphicUnit.h:919
TRailGraphics::gl123
Graphics::TBitmap * gl123
Definition: GraphicUnit.h:602
TOnePrefDir::SaveSearchVector
void SaveSearchVector(int Caller, std::ofstream &VecFile)
Save the search vector to a file.
Definition: TrackUnit.cpp:12750
TRailGraphics::gl48
Graphics::TBitmap * gl48
Definition: GraphicUnit.h:666
TOneRoute::ForceCancelRoute
void ForceCancelRoute(int Caller)
Cancel a route immediately if a train occupies it when travelling in the wrong direction (or occupies...
Definition: TrackUnit.cpp:17368
TTrack::SaveChangingLCVector
void SaveChangingLCVector(int Caller, std::ofstream &OutFile)
Save all changing vector values (used for error file)
Definition: TrackUnit.cpp:3639
TTrackElement::PlotVariableTrackElement
void PlotVariableTrackElement(int Caller, TDisplay *Disp) const
Plot the element on the display 'variable' indicates that the element may be named and if so may be p...
Definition: TrackUnit.cpp:169
TOnePrefDir::StorePrefDirElement
void StorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
Store a single pref dir element in the vector & map.
Definition: TrackUnit.cpp:13338
TTrack::SaveUserGraphics
void SaveUserGraphics(int Caller, std::ofstream &VecFile)
save graphics
Definition: TrackUnit.cpp:11294
TTrack::ThisNamedLocationLongEnoughForSplit
bool ThisNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName, int FirstNamedElementPos, int &SecondNamedElementPos, int &FirstNamedLinkedElementPos, int &SecondNamedLinkedElementPos)
See above under 'OneNamedLocationLongEnoughForSplit'.
Definition: TrackUnit.cpp:10669
TGraphicElement::LoadOriginalScreenGraphic
void LoadOriginalScreenGraphic(int Caller)
Load original graphic from the screen for point flashing or route start markers.
Definition: TrackUnit.cpp:1780
TRailGraphics::sm109
Graphics::TBitmap * sm109
Definition: GraphicUnit.h:778
TTrack::SelectVectorSize
unsigned int SelectVectorSize()
Return the number of selected active and inactive track elements (via menu items 'Edit' and 'Select')
Definition: TrackUnit.h:913
TRailGraphics::bm74yellow
Graphics::TBitmap * bm74yellow
Definition: GraphicUnit.h:496
TTrack::Tag78Array
int Tag78Array[25][3]
Definition: TrackUnit.h:577
TTrack::PlotGap
void PlotGap(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plots a gap on screen - may be set or unset.
Definition: TrackUnit.cpp:5921
TPrefDirElement::GetDirectionPrefDirGraphicPtr
Graphics::TBitmap * GetDirectionPrefDirGraphicPtr() const
picks up the EntryDirectionGraphicPtr for preferred directions
Definition: TrackUnit.cpp:1029
TOnePrefDir::LoadPrefDir
void LoadPrefDir(int Caller, std::ifstream &VecFile)
Load a vector and map of preferred directions from the file.
Definition: TrackUnit.cpp:12570
Under
@ Under
Definition: TrackUnit.h:75
TRailGraphics::bm59
Graphics::TBitmap * bm59
Definition: GraphicUnit.h:450
TOneRoute::PointsToBeChanged
bool PointsToBeChanged(int Caller) const
Called by GetNextNonPreferredRouteElement and GetNextPreferredRouteElement to check whether or not an...
Definition: TrackUnit.cpp:16878
TTrack::TrackVector
TTrackVector TrackVector
Definition: TrackUnit.h:801
TRailGraphics::gl84
Graphics::TBitmap * gl84
Definition: GraphicUnit.h:710
TTrack::TActiveLevelCrossing::BaseElementSpeedTag
int BaseElementSpeedTag
SpeedTag value for the base element of a level crossing.
Definition: TrackUnit.h:622
TTrackElement::operator!=
bool operator!=(TTrackElement RHElement)
non-equivalence operator
Definition: TrackUnit.cpp:155
TTrack::ResetConnClkCheckUnsetGapJumps
bool ResetConnClkCheckUnsetGapJumps(int Caller)
Sets all Conns and CLks to -1 except for gapjumps that match and are properly set,...
Definition: TrackUnit.cpp:2896
TOnePrefDir::GetModifiablePrefDirElementAt
TPrefDirElement & GetModifiablePrefDirElementAt(int Caller, int At)
Return a modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:11445
TOnePrefDir::SearchForPrefDir
bool SearchForPrefDir(int Caller, TTrackElement TrackElement, int XLinkPos, int RequiredPosition)
Try to find a selected element from a given start position. Enter with CurrentTrackElement stored in ...
Definition: TrackUnit.cpp:11765
TRailGraphics::sm96
Graphics::TBitmap * sm96
Definition: GraphicUnit.h:885
TGraphicElement
Allows a single Width x Height graphic to change and change back independently of the remaining displ...
Definition: TrackUnit.h:427
TTrackElement::CallingOnSet
bool CallingOnSet
Used for for signals only when a train is being called on - used to plot the position lights.
Definition: TrackUnit.h:134
TUtilities::SaveFileInt
void SaveFileInt(std::ofstream &OutFile, int SaveInt)
stores the int value to the file, then a CR
Definition: Utilities.cpp:121
TrainController
TTrainController * TrainController
the object pointer, one object only - created in InterfaceUnit
Definition: TrainUnit.cpp:54
TTrack::OneNamedLocationLongEnoughForSplit
bool OneNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName)
Definition: TrackUnit.cpp:10563
Lead
@ Lead
Definition: TrackUnit.h:75
TTrack::TrackElementPresentAtHV
bool TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if a track element present (not inactive elements - see InactiveTrackElementPrese...
Definition: TrackUnit.cpp:5786
TGraphicElement::LoadOriginalExistingGraphic
void LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
Load red or green gap flashing graphic from the stored bitmaps.
Definition: TrackUnit.cpp:1814
TOnePrefDir::CalcDistanceAndSpeed
void CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
Used when setting element lengths, returns in &OverallDistance the overall distance for the selected ...
Definition: TrackUnit.cpp:13586
TTrack::PlotContinuation
void PlotContinuation(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plots a continuation on screen, may have overlays if a multiplayer session.
Definition: TrackUnit.cpp:5998
TTrack::GetHLocMin
int GetHLocMin()
Definition: TrackUnit.h:867
TTextHandler::TextPtrAt
TTextItem * TextPtrAt(int Caller, int At)
return the text item at position 'At' in TextVector (carries out range checking)
Definition: TextUnit.cpp:555
TUtilities::CheckFileInt
bool CheckFileInt(std::ifstream &InFile, int Lowest, int Highest)
checks that the value is an int lying between Lowest & Highest (inclusive), returns true for success
Definition: Utilities.cpp:238
TTrack::TrackPush
void TrackPush(int Caller, TTrackElement TrackElement)
Insert TrackElement into the relevant vector and map, and, if named, insert the name in LocationNameM...
Definition: TrackUnit.cpp:5578
TTrack::IsBarrierDownVectorAtHVManual
bool IsBarrierDownVectorAtHVManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
True if there is a vector entry at H & V that is set to manual (TypeOfRoute == 2) and returns the vec...
Definition: TrackUnit.cpp:6400
TFixedTrackPiece::FixedNamedLocationElement
bool FixedNamedLocationElement
true for an element that can be named (platforms, concourse, footcrossings & non-station named loacti...
Definition: TrackUnit.h:85
TOnePrefDir::PrefDirSearchLimit
static const int PrefDirSearchLimit
limit to the number of elements searched in attempting to find a preferred direction
Definition: TrackUnit.h:1329
TTrack::GetTrackVectorIteratorFromNamePosition
TTrackVectorIterator GetTrackVectorIteratorFromNamePosition(int Caller, int Position)
Takes an adjusted vector position value from either vector (if active, Position = -TruePos -1,...
Definition: TrackUnit.cpp:9286
TRailGraphics::bm70grounddblwhite
Graphics::TBitmap * bm70grounddblwhite
Definition: GraphicUnit.h:468
TRailGraphics::bm70green
Graphics::TBitmap * bm70green
Definition: GraphicUnit.h:469
TRailGraphics::gl115
Graphics::TBitmap * gl115
Definition: GraphicUnit.h:593
TTrack::Up
@ Up
Definition: TrackUnit.h:607
TRailGraphics::sm89
Graphics::TBitmap * sm89
Definition: GraphicUnit.h:877
TTrack::NextTrackElementPtr
TTrackVectorIterator NextTrackElementPtr
track vector iterator used during cycling through a track vector
Definition: TrackUnit.h:803
TTrack::Tag130Array
int Tag130Array[8][3]
Definition: TrackUnit.h:581
TTrack::BlankElementAt
bool BlankElementAt(int Caller, int At) const
True for a blank (SpeedTag == 0) element at a specific Trackvector position, no longer used after Tra...
Definition: TrackUnit.cpp:10542
TRailGraphics::sm127
Graphics::TBitmap * sm127
Definition: GraphicUnit.h:938
TOneRoute
A descendent of TOnePrefDir used for routes. Used during contruction of a route (ConstructRoute) and ...
Definition: TrackUnit.h:1474
TDisplay::PlotSignalBlankOnBitmap
void PlotSignalBlankOnBitmap(int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap *Bitmap, bool RHSFlag)
Definition: DisplayUnit.cpp:378
TTrack::NamedLocationElementAt
bool NamedLocationElementAt(int Caller, int HLoc, int VLoc)
True if the active or inactive TrackElement at HLoc & VLoc has its FixedNamedLocationElement member t...
Definition: TrackUnit.cpp:8578
TAllRoutes::TLockedRouteVectorIterator
std::vector< TLockedRouteClass >::iterator TLockedRouteVectorIterator
Definition: TrackUnit.h:1629
TTrack::LCFoundInAutoSigsRoute
bool LCFoundInAutoSigsRoute
true if found an LC during an automatic route search
Definition: TrackUnit.h:738
TPrefDirElement::XLink
int XLink
Definition: TrackUnit.h:200
TOneRoute::SetRouteFlashValues
void SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
After a route has been selected successfully this function sets all RouteFlash (see above) values app...
Definition: TrackUnit.cpp:17435
TAllRoutes::TRouteType
TRouteType
Definition: TrackUnit.h:1618
TRailGraphics::bm133
Graphics::TBitmap * bm133
Definition: GraphicUnit.h:363
TRailGraphics::sm135
Graphics::TBitmap * sm135
Definition: GraphicUnit.h:795
Crossover
@ Crossover
Definition: TrackUnit.h:65
TTrack::SetLinkedManualLCs
void SetLinkedManualLCs(int Caller, int HLoc, int VLoc)
Set all TypeOfRoute values to 2 for all linked LCs to indicate manually lowered.
Definition: TrackUnit.cpp:6286
TRailGraphics::bm71green
Graphics::TBitmap * bm71green
Definition: GraphicUnit.h:475
TRailGraphics::bm51
Graphics::TBitmap * bm51
Definition: GraphicUnit.h:446
TTrack::UGME
TUserGraphicMapEntry UGME
an entry for the UserGraphicMap
Definition: TrackUnit.h:805
TRailGraphics::gl21
Graphics::TBitmap * gl21
Definition: GraphicUnit.h:637
TTrack::ElementInLNDone2MultiMap
bool ElementInLNDone2MultiMap(int Caller, int MapPos)
True if the element defined by MapPos is present in LNDone2MultiMap, used during location naming.
Definition: TrackUnit.cpp:8524
TRailGraphics::sm137
Graphics::TBitmap * sm137
Definition: GraphicUnit.h:797
TTrack::IsLCBarrierFlashingAtHV
bool IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
True if barrier is in process of opening or closing at H & V.
Definition: TrackUnit.cpp:7291
TTrack::IsPlatformOrNamedNonStationLocationPresent
bool IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location or platform at HLoc & VLoc.
Definition: TrackUnit.cpp:9953
TRailGraphics::bm68CallingOn
Graphics::TBitmap * bm68CallingOn
Definition: GraphicUnit.h:452
Signal
@ Signal
Definition: TrackUnit.h:75
TTrack::VLocMin
int VLocMin
Definition: TrackUnit.h:568
TTrack::LevelCrossingAllowed
Set< int, 1, 146 > LevelCrossingAllowed
sets of valid TrackElements for placement of platforms and non-station named locations
Definition: TrackUnit.h:586
TRailGraphics::bm69grounddblwhite
Graphics::TBitmap * bm69grounddblwhite
Definition: GraphicUnit.h:461
TTrack::ContinuationNameMap
std::map< AnsiString, char > ContinuationNameMap
map of all continuation names, char is a dummy
Definition: TrackUnit.h:772
TAllRoutes::GetRouteTypeAndNumber
TRouteType GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:17885
TTrackElement::TrainIDOnBridgeTrackPos01
int TrainIDOnBridgeTrackPos01
Definition: TrackUnit.h:152
TTrack::TFixedTrackArray::TFixedTrackArray
TFixedTrackArray()
Array constructor.
Definition: TrackUnit.cpp:1548
TOnePrefDir::CheckOnePrefDir
bool CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile)
Called before PrefDir loading as part of the FileIntegrityCheck function in case there is an error in...
Definition: TrackUnit.cpp:12620
TRailGraphics::bm78Striped
Graphics::TBitmap * bm78Striped
Definition: GraphicUnit.h:506
TTrack::TrainOnLink
bool TrainOnLink(int Caller, int HLoc, int VLoc, int Link, int &TrainID)
New at v1.2.0; checks whether a train present at input location and link and returns its ID if so.
Definition: TrackUnit.cpp:11190
TTrack::ResetAnyNonMatchingGaps
void ResetAnyNonMatchingGaps(int Caller)
Called by EraseTrackElement after the element has been erased and the vector positions changed,...
Definition: TrackUnit.cpp:4624
TTrack::GapPos
int GapPos
Definition: TrackUnit.h:566
TTrack::TrackElementAt
TTrackElement & TrackElementAt(int Caller, int At)
A range-checked version of TrackVector.at(At)
Definition: TrackUnit.cpp:10514
TGraphicElement::Width
int Width
Definition: TrackUnit.h:434
TAllRoutes::RouteLockingRequired
bool RouteLockingRequired(int Caller, int RouteNumber, int RouteTruncatePosition)
Route locking is required (returns true) if a moving train is within 3 signals back from the RouteTru...
Definition: TrackUnit.cpp:18793
TRailGraphics::bmGreenEllipse
Graphics::TBitmap * bmGreenEllipse
Definition: GraphicUnit.h:520
TAllRoutes::GetRouteVectorNumber
int GetRouteVectorNumber(int Caller, IDInt RouteID)
Returns a route's position in AllRoutesVector from its ID, throws an error if a matching route isn't ...
Definition: TrackUnit.cpp:19003
TAllRoutes::GetRouteTypeAndGraphics
TRouteType GetRouteTypeAndGraphics(int Caller, int TrackVectorPosition, int LinkPos, Graphics::TBitmap *&EXGraphicPtr, Graphics::TBitmap *&EntryDirectionGraphicPtr)
Examines Route2MultiMap for the element at TrackVectorPosition with LinkPos (can be entry or exit).
Definition: TrackUnit.cpp:17711
TTrack::ChangingLCVector
TActiveLCVector ChangingLCVector
vector of values for changing level crossings - i.e. barriers in course of being raised or lowered
Definition: TrackUnit.h:778
TRailGraphics::bm73green
Graphics::TBitmap * bm73green
Definition: GraphicUnit.h:488
TTrainController::StopTTClockFlag
bool StopTTClockFlag
when true the timetable clock is stopped, used for messages display and train popup menu display etc
Definition: TrainUnit.h:789
TRailGraphics::gl107
Graphics::TBitmap * gl107
Definition: GraphicUnit.h:584
TPrefDirElement::GetRouteGraphicPtr
Graphics::TBitmap * GetRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute)
picks up the appropriate route graphic
Definition: TrackUnit.cpp:656
TRailGraphics::bm53
Graphics::TBitmap * bm53
Definition: GraphicUnit.h:447
TUtilities::CheckAndReadFileString
bool CheckAndReadFileString(std::ifstream &InFile, AnsiString &OutString)
checks that the value is a string ('0' or ' ' (CRLF) accepted as delimiters), returns true for succes...
Definition: Utilities.cpp:529
TRailGraphics::sm12
Graphics::TBitmap * sm12
Definition: GraphicUnit.h:785
TUserGraphicItem::FileName
AnsiString FileName
Definition: DisplayUnit.h:33
TOneRoute::GetNextPreferredRouteElement
bool GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignals, bool AutoSigsFlag, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks that lie on preferred directions between the route start element a...
Definition: TrackUnit.cpp:14416
TTrack::TTrackMapIterator
TTrackMap::iterator TTrackMapIterator
Definition: TrackUnit.h:654
TTrack::WriteGraphicsToImage
void WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by SaveImageNoGridMenuItemClick, SaveImageAndGridMenuItemClick amd SaveImageAndPrefDirsMenuIte...
Definition: TrackUnit.cpp:4141
TTrack::PlotPastedTrackElementWithAttributes
void PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks)
new at v2.2.0 - as PlotAndAddTrackElement but keeping speed & length attributes (for pasting) and als...
Definition: TrackUnit.cpp:2359
TTrack::TLocationNameMultiMapIterator
TLocationNameMultiMap::iterator TLocationNameMultiMapIterator
Definition: TrackUnit.h:687
TRailGraphics::bm70CallingOn
Graphics::TBitmap * bm70CallingOn
Definition: GraphicUnit.h:465
TTrack::RebuildLocationNameMultiMap
void RebuildLocationNameMultiMap(int Caller)
Clears the existing LocationNameMultiMap and rebuilds it from TrackVector and InactiveTrackVector....
Definition: TrackUnit.cpp:9426
TOnePrefDir::EveryPrefDirMarker
void EveryPrefDirMarker(int Caller, TDisplay *Disp)
Similar to PrefDirMarker but used only to mark EveryPrefDir - red for unidirectional PrefDir & green ...
Definition: TrackUnit.cpp:12388
TRailGraphics::gl124
Graphics::TBitmap * gl124
Definition: GraphicUnit.h:603
TRailGraphics::bm32
Graphics::TBitmap * bm32
Definition: GraphicUnit.h:407
TRailGraphics::sm88
Graphics::TBitmap * sm88
Definition: GraphicUnit.h:876
TTrack::SetTrackFinished
void SetTrackFinished(bool Value)
Definition: TrackUnit.h:940
TTrack::GetInactiveTrackElementFromTrackMap
TTrackElement & GetInactiveTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the inactive element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5762
TAllRoutes::LoadRoutes
bool LoadRoutes(int Caller, std::ifstream &InFile)
Loads the routes from a session file.
Definition: TrackUnit.cpp:19086
TRailGraphics::gl105
Graphics::TBitmap * gl105
Definition: GraphicUnit.h:582
TOneRoute::StartElement1
TPrefDirElement StartElement1
Definition: TrackUnit.h:1516
TRailGraphics::sm75
Graphics::TBitmap * sm75
Definition: GraphicUnit.h:925
TRailGraphics::sm115
Graphics::TBitmap * sm115
Definition: GraphicUnit.h:783
TOneRoute::ReqPosRouteID
IDInt ReqPosRouteID
session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1505
TRailGraphics::sm53
Graphics::TBitmap * sm53
Definition: GraphicUnit.h:842
TTrack::PlotRaisedLinkedLevelCrossingBarriers
void PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot & close (to trains) all level crossings linked to TrackElement - always plots as red - auto.
Definition: TrackUnit.cpp:6989
TRailGraphics::bm71CallingOn
Graphics::TBitmap * bm71CallingOn
Definition: GraphicUnit.h:471
TTrack::LCFoundInRouteBuildingFlag
bool LCFoundInRouteBuildingFlag
true if a route set through an LC that is closed to trains (& therefore needs to be opened)
Definition: TrackUnit.h:744
TRailGraphics::DirectionSigRouteGraphicsPtr
Graphics::TBitmap * DirectionSigRouteGraphicsPtr[10]
preferred direction route marker arrows
Definition: GraphicUnit.h:1044
TRailGraphics::DirectionRouteAutoSigsGraphicsPtr
Graphics::TBitmap * DirectionRouteAutoSigsGraphicsPtr[10]
autosigs route marker arrows
Definition: GraphicUnit.h:1046
TRailGraphics::bm93set
Graphics::TBitmap * bm93set
Definition: GraphicUnit.h:514
TTrack::GetTrackVectorPositionFromString
int GetTrackVectorPositionFromString(int Caller, AnsiString String, bool GiveMessages)
Takes the ElementID value (an AnsiString) (e.g. "8-13", "N43-N127", etc) and returns the correspondin...
Definition: TrackUnit.cpp:7822
TOneRoute::TRouteFlash::PlotRouteOriginal
void PlotRouteOriginal(int Caller)
display the original (non route-coloured) graphic
Definition: TrackUnit.cpp:17527
TTrack::TTrackMapEntry
std::pair< THVPair, unsigned int > TTrackMapEntry
Definition: TrackUnit.h:655
TRailGraphics::bm37
Graphics::TBitmap * bm37
Definition: GraphicUnit.h:422
TTrack::ResetLevelCrossings
void ResetLevelCrossings(int Caller)
Set all LC attributes to 0 (closed to trains)
Definition: TrackUnit.cpp:7364
TRailGraphics::sm139
Graphics::TBitmap * sm139
Definition: GraphicUnit.h:799
Erase
@ Erase
Definition: TrackUnit.h:66
TRailGraphics::sm57
Graphics::TBitmap * sm57
Definition: GraphicUnit.h:846
TRailGraphics::bm29
Graphics::TBitmap * bm29
Definition: GraphicUnit.h:398
TRailGraphics::bm72grounddblwhite
Graphics::TBitmap * bm72grounddblwhite
Definition: GraphicUnit.h:480
TTrack::IsTrackLinked
bool IsTrackLinked(int Caller)
True if track has been successfully linked (not used any more)
Definition: TrackUnit.cpp:5383
TTrack::NewVector
TTrackVector NewVector
Definition: TrackUnit.h:801
TAllRoutes::LockedRouteTruncateTrackVectorPosition
unsigned int LockedRouteTruncateTrackVectorPosition
Definition: TrackUnit.h:1668
TUtilities::SaveFileDouble
void SaveFileDouble(std::ofstream &OutFile, double SaveDouble)
converts the double value to a string (if double stored directly it is truncated to 6 digits) then st...
Definition: Utilities.cpp:127
TRailGraphics::sm39
Graphics::TBitmap * sm39
Definition: GraphicUnit.h:826
TRailGraphics::sm85
Graphics::TBitmap * sm85
Definition: GraphicUnit.h:873
TRailGraphics::gl112
Graphics::TBitmap * gl112
Definition: GraphicUnit.h:590
TOnePrefDir::GetExactMatchFrom4MultiMap
TPrefDir4MultiMapIterator GetExactMatchFrom4MultiMap(int Caller, unsigned int PrefDirVectorPosition, bool &FoundFlag)
Retrieves a PrefDir4MultiMap iterator to the PrefDir element at PrefDirVectorPosition....
Definition: TrackUnit.cpp:13408
TTrack::TActiveLevelCrossing::TypeOfRoute
int TypeOfRoute
route type - 0 = nonsignals, 1 = preferred direction (can't have autosigs), 2 no route,...
Definition: TrackUnit.h:614
TTrack::GetAnyElementOppositeLinkPos
int GetAnyElementOppositeLinkPos(int Caller, int TrackVectorPosition, int LinkPos, bool &Derail)
Return the opposite link position for the element at TrackVectorPosition with link position LinkPos,...
Definition: TrackUnit.cpp:11102
Parapet
@ Parapet
Definition: TrackUnit.h:66
TRailGraphics::bm54
Graphics::TBitmap * bm54
Definition: GraphicUnit.h:448
TAllRoutes::GetFixedRouteAt
const TOneRoute & GetFixedRouteAt(int Caller, int At) const
Returns a constant reference to the route at AllRoutesVector position 'At', after performing range ch...
Definition: TrackUnit.cpp:17554
TUtilities::clTransparent
TColor clTransparent
the display background colour, can be white, black or dark blue
Definition: Utilities.h:65
TRailGraphics::sm14
Graphics::TBitmap * sm14
Definition: GraphicUnit.h:800
TRailGraphics::bmStraightEWSignalBlank
Graphics::TBitmap * bmStraightEWSignalBlank
Definition: GraphicUnit.h:1008
TPrefDirElement::GetELinkPos
int GetELinkPos() const
Returns the ELink array position.
Definition: TrackUnit.h:269
TTrack::CheckLocationNameMultiMap
void CheckLocationNameMultiMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:9095
TOneRoute::TRouteFlash::PlotRouteOverlay
void PlotRouteOverlay(int Caller)
display the overlay (route-coloured) graphic
Definition: TrackUnit.cpp:17500
TRailGraphics::bm138
Graphics::TBitmap * bm138
Definition: GraphicUnit.h:378
TRailGraphics::sm79striped
Graphics::TBitmap * sm79striped
Definition: GraphicUnit.h:866
TTrack::InactiveTrackVector
TTrackVector InactiveTrackVector
Definition: TrackUnit.h:801
TAllRoutes::DecrementRouteElementNumbersInRoute2MultiMap
void DecrementRouteElementNumbersInRoute2MultiMap(int Caller, int RouteNumber, unsigned int ErasedElementNumber)
After a route element has been erased from the relevant PrefDirVector and from Route2MultiMap,...
Definition: TrackUnit.cpp:18420
TRailGraphics::gl126
Graphics::TBitmap * gl126
Definition: GraphicUnit.h:605
TRailGraphics::sm119
Graphics::TBitmap * sm119
Definition: GraphicUnit.h:930
TTrack::ActiveTrackElementNameMap
TActiveTrackElementNameMap ActiveTrackElementNameMap
< map of coupled continuations
Definition: TrackUnit.h:776
TRailGraphics::sm138
Graphics::TBitmap * sm138
Definition: GraphicUnit.h:798
TTrackElement::HLoc
int HLoc
Definition: TrackUnit.h:146
TRailGraphics::bm72grounddblred
Graphics::TBitmap * bm72grounddblred
Definition: GraphicUnit.h:479
TRailGraphics::sm34
Graphics::TBitmap * sm34
Definition: GraphicUnit.h:821
TDisplay::PlotPointBlank
void PlotPointBlank(int Caller, int HLoc, int VLoc)
Definition: DisplayUnit.cpp:247
TRailGraphics::ConcourseStriped
Graphics::TBitmap * ConcourseStriped
Definition: GraphicUnit.h:550
TRailGraphics::PointModeGraphicsPtr
Graphics::TBitmap * PointModeGraphicsPtr[32][2]
for point fillets - 32 sets of points, each with two fillets
Definition: GraphicUnit.h:1049
TTrack::SigTableTwoAspect
TSigElement SigTableTwoAspect[40]
new at version 0.6 for two aspect
Definition: TrackUnit.h:721
TRailGraphics::sm27
Graphics::TBitmap * sm27
Definition: GraphicUnit.h:813
TTrainController::LogActionError
void LogActionError(int Caller, AnsiString HeadCode, AnsiString OtherHeadCode, TActionEventType ActionEventType, AnsiString LocationID)
Send an error message to the performance log and file, and as a warning if appropriate.
Definition: TrainUnit.cpp:14983
TRailGraphics::sm5
Graphics::TBitmap * sm5
Definition: GraphicUnit.h:838
TTrackElement::LCPlotted
bool LCPlotted
Utility marker to avoid plotting every element of a multitrack LC during ClearandRebuildRailway.
Definition: TrackUnit.h:136
TPrefDirElement::EXNumber
int EXNumber
used to facilitate identification of the appropriate preferred direction or route graphic
Definition: TrackUnit.h:202
TTrack::NumberOfPlatforms
int NumberOfPlatforms(int Caller, AnsiString LocationName)
Returns the number of separate platforms (not platform elements) at a given location,...
Definition: TrackUnit.cpp:11322
TOnePrefDir::PrefDirMarker
void PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp) const
PrefDir and route track marker, including direction markers.
Definition: TrackUnit.cpp:12315
TRailGraphics::bm78
Graphics::TBitmap * bm78
Definition: GraphicUnit.h:505
TTruncateReturnType
TTruncateReturnType
< a flag used during route truncation to indicate the nature of the selected element,...
Definition: TrackUnit.h:1278
TRailGraphics::bm75CallingOn
Graphics::TBitmap * bm75CallingOn
Definition: GraphicUnit.h:497
TOneRoute::SetLCChangeValues
void SetLCChangeValues(int Caller, bool PrefDirRoute)
After a route has been selected successfully this function sets all LC change values appropriately fo...
Definition: TrackUnit.cpp:17463
TRailGraphics::gl130
Graphics::TBitmap * gl130
Definition: GraphicUnit.h:611
TRailGraphics::bm71yellow
Graphics::TBitmap * bm71yellow
Definition: GraphicUnit.h:476
TRailGraphics::LCRHSVerMan
Graphics::TBitmap * LCRHSVerMan
Definition: GraphicUnit.h:746
TTrack
Definition: TrackUnit.h:544
TOnePrefDir::SearchLimitHighH
int SearchLimitHighH
Definition: TrackUnit.h:1337
TTrack::TwoAspectBuild
@ TwoAspectBuild
Definition: TrackUnit.h:848
TOnePrefDir::PrefDirVector
TPrefDirVector PrefDirVector
Definition: TrackUnit.h:1368
TAllRoutes::SetTrailingSignalsOnAutoSigsRoute
void SetTrailingSignalsOnAutoSigsRoute(int Caller, int TrackVectorPosition, int XLinkPos)
Enter with signal at TrackVectorElement already set to red by the passing train.
Definition: TrackUnit.cpp:18569
clB5G5R5
#define clB5G5R5
Definition: GraphicUnit.h:286
TUtilities::TimeStamp
AnsiString TimeStamp()
creates a string of the form 'hh:mm:ss' for use in call & event logging
Definition: Utilities.cpp:73
TAllRoutes::TLockedRouteClass::RouteNumber
int RouteNumber
the vector position number of the relevant route in AllRoutesVector
Definition: TrackUnit.h:1605
TTrack::ActiveMapCheck
bool ActiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
Used to check the validity of footcrossing links.
Definition: TrackUnit.cpp:8123
TRailGraphics::gl2
Graphics::TBitmap * gl2
Definition: GraphicUnit.h:635
TTrack::Tag146Array
int Tag146Array[8][3]
Definition: TrackUnit.h:584
TRailGraphics::sm65
Graphics::TBitmap * sm65
Definition: GraphicUnit.h:855
TRailGraphics::gl47
Graphics::TBitmap * gl47
Definition: GraphicUnit.h:665
TRailGraphics::LCBothHorMan
Graphics::TBitmap * LCBothHorMan
Definition: GraphicUnit.h:741
TRailGraphics::sm78striped
Graphics::TBitmap * sm78striped
Definition: GraphicUnit.h:864
TTrackElement::ActiveTrackElementName
AnsiString ActiveTrackElementName
Location name used either in the timetable or for a continuation (continuation names not used in time...
Definition: TrackUnit.h:127
TRailGraphics::sm33
Graphics::TBitmap * sm33
Definition: GraphicUnit.h:820
TRailGraphics::bm94set
Graphics::TBitmap * bm94set
Definition: GraphicUnit.h:516
TRailGraphics::gl76Striped
Graphics::TBitmap * gl76Striped
Definition: GraphicUnit.h:700
TPrefDirElement::XLinkPos
int XLinkPos
exit link number & array position
Definition: TrackUnit.h:200
TAllRoutes::StoreOneRouteAfterSessionLoad
void StoreOneRouteAfterSessionLoad(int Caller, TOneRoute *Route)
A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector after a session load....
Definition: TrackUnit.cpp:18060
TPrefDirElement::EntryDirectionGraphicPtr
Graphics::TBitmap * EntryDirectionGraphicPtr
pointers to the appropriate entry/exit graphic, or direction marker graphic, for preferred directions...
Definition: TrackUnit.h:208
TTrack::LoadTrack
void LoadTrack(int Caller, std::ifstream &VecFile, bool &GraphicsFollow)
Load track elements (active & inactive) from the file into the relevant vectors and maps,...
Definition: TrackUnit.cpp:2976
TRailGraphics::bm65
Graphics::TBitmap * bm65
Definition: GraphicUnit.h:451
TTrainController::LogEvent
void LogEvent(AnsiString Str)
store Str to the event log - moved from TUtilities for v0.6 so can record the tt clock value
Definition: TrainUnit.cpp:9090
TRailGraphics::sm74
Graphics::TBitmap * sm74
Definition: GraphicUnit.h:924
TTrack::PlotSignalPlatforms
void PlotSignalPlatforms(int Caller, int HLoc, int VLoc, TDisplay *Disp)
Plot platforms if any for a signal graphic - plotted before signal so shows through transparent signa...
Definition: TrackUnit.cpp:6180
TTrack::PlotAndAddTrackElement
void PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackPlottedFlag, bool InternalChecks)
Called during track building or pasting, when an element identified by CurrentTag (i....
Definition: TrackUnit.cpp:2111
TUtilities::SaveFileString
void SaveFileString(std::ofstream &OutFile, AnsiString SaveString)
stores the string value to the file, then a '0' delimiter then a CR
Definition: Utilities.cpp:135
TTrack::Tag145Array
int Tag145Array[8][3]
Definition: TrackUnit.h:583
TRailGraphics::LCRHSVer
Graphics::TBitmap * LCRHSVer
Definition: GraphicUnit.h:739
TTrackElement::TwoAspect
@ TwoAspect
Definition: TrackUnit.h:157
TTrackElement::TTrackElement
TTrackElement()
Constructor for non-specific default element. Use high neg numbers for 'unset' h & v as can go high n...
Definition: TrackUnit.h:163
TRailGraphics::sm76
Graphics::TBitmap * sm76
Definition: GraphicUnit.h:859
TTrack::GapFlashRed
TGraphicElement * GapFlashRed
the red & green circle graphics used to show where the gaps are
Definition: TrackUnit.h:784
TTrack::TryToConnectTrack
bool TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
Handles all tasks associated with track linking, returns true if successful (see also LinkTrack & Lin...
Definition: TrackUnit.cpp:2577
TPrefDirElement::ELinkPos
int ELinkPos
entry link number & array position
Definition: TrackUnit.h:198
TAllRoutes::TLockedRouteClass
Handles routes that are locked because of approaching trains.
Definition: TrackUnit.h:1603
TTrack::SetElementID
void SetElementID(int Caller, TTrackElement &TrackElement)
Convert the position values for the TrackElement into an identification string and load in ElementID.
Definition: TrackUnit.cpp:7786
TRailGraphics::bm72yellow
Graphics::TBitmap * bm72yellow
Definition: GraphicUnit.h:482
TOnePrefDir::EndPossible
bool EndPossible(int Caller, bool &LeadingPoints)
Used when setting preferred directions, true if able to finish at the last selected element (can't fi...
Definition: TrackUnit.cpp:12103
TOnePrefDir::ConsolidatePrefDirs
void ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
Used when a preferred direction has been set to add all the elements to EveryPrefDir,...
Definition: TrackUnit.cpp:12881
TTrack::Tag131Array
int Tag131Array[4][3]
Definition: TrackUnit.h:582
TOneRoute::TRouteFlashElement::TrackVectorPosition
int TrackVectorPosition
element values
Definition: TrackUnit.h:1480
TTrack::RetrieveStripedNamedLocationGraphicsWhereRelevant
Graphics::TBitmap * RetrieveStripedNamedLocationGraphicsWhereRelevant(int Caller, TTrackElement TrackElement)
Return a pointer to the striped (i.e. when unnamed) graphic corresponding to TrackElement,...
Definition: TrackUnit.cpp:10451
TTrack::AddName
void AddName(int Caller, TTrackVectorIterator TrackElement, AnsiString Name)
TrackElement.LocationName becomes 'Name' (for active and inactive elements) and, if TrackElement is a...
Definition: TrackUnit.cpp:8487
IDInt
Definition: TrackUnit.h:493
TTrain::GetLeadElement
void GetLeadElement(int Caller)
Called when a train is about to leave an element and move onto another.
Definition: TrainUnit.cpp:2402
TRailGraphics::gl110
Graphics::TBitmap * gl110
Definition: GraphicUnit.h:588
TAllRoutes::GetModifiableRouteAtIDNumber
TOneRoute & GetModifiableRouteAtIDNumber(int Caller, IDInt RouteID)
Returns a modifiable reference to the route with ID number RouteID. If no route is found with that ID...
Definition: TrackUnit.cpp:19054
TRailGraphics::gl130Striped
Graphics::TBitmap * gl130Striped
Definition: GraphicUnit.h:612
TRailGraphics::sm133
Graphics::TBitmap * sm133
Definition: GraphicUnit.h:793
TTrack::FindAndHighlightAnUnsetGap
bool FindAndHighlightAnUnsetGap(int Caller)
True if there is an unset gap, and if so it is marked with a red circle, used during gap setting.
Definition: TrackUnit.cpp:4428
TDisplay
Definition: DisplayUnit.h:48
TTrack::PlotSmallRailway
void PlotSmallRailway(int Caller, TDisplay *Disp)
Plot on screen the zoomed-out railway.
Definition: TrackUnit.cpp:10201
TTrack::LinkTrackNoMessages
bool LinkTrackNoMessages(int Caller, bool FinalCall)
Attempt to link the track and return true if successful, don't issue any screen messages....
Definition: TrackUnit.cpp:5128
TTrackElement::ConnLinkPos
int ConnLinkPos[4]
Connecting element link position (i.e. array positions of the connecting element links,...
Definition: TrackUnit.h:144
TTrainController::ContinuationAutoSigVector
TContinuationAutoSigVector ContinuationAutoSigVector
vector for TContinuationAutoSigEntry objects
Definition: TrainUnit.h:862
TRailGraphics::sm129striped
Graphics::TBitmap * sm129striped
Definition: GraphicUnit.h:787
TRailGraphics::sm48
Graphics::TBitmap * sm48
Definition: GraphicUnit.h:836
TGraphicElement::OverlayGraphic
Graphics::TBitmap * OverlayGraphic
original and temporary overlay graphics
Definition: TrackUnit.h:436
TAllRoutes::CheckForLoopingRoute
bool CheckForLoopingRoute(int Caller, int EndPosition, int EndXLinkPos, int StartPosition)
Functions defined in .cpp file.
Definition: TrackUnit.cpp:19151
TTrack::TTrack
TTrack()
Constructor, only one object of this class.
Definition: TrackUnit.cpp:1126
TTrack::FindNamedElementInLocationNameMultiMap
TLocationNameMultiMapIterator FindNamedElementInLocationNameMultiMap(int Caller, AnsiString LocationName, TTrackVectorIterator TrackElement, AnsiString &ErrorString)
Searches LocationNameMultiMap to check if the element pointed to by the TTrackVectorIterator has the ...
Definition: TrackUnit.cpp:9209
TTrackElement::operator==
bool operator==(TTrackElement RHElement)
equivalence operator
Definition: TrackUnit.cpp:141
TTrack::GapHLoc
int GapHLoc
Definition: TrackUnit.h:566
TFixedTrackPiece::Config
TConfiguration Config[4]
the type of link - see TConfiguration above
Definition: TrackUnit.h:96
TTrack::CheckGapMap
void CheckGapMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:7733
NotInRoute
@ NotInRoute
Definition: TrackUnit.h:1279
TDisplay::GetRectangle
void GetRectangle(int Caller, TRect DestRect, TRect SourceRect, Graphics::TBitmap *&OriginalGraphic)
Definition: DisplayUnit.cpp:227
TTrackElement::TrainIDOnElement
int TrainIDOnElement
Definition: TrackUnit.h:152
TRailGraphics::smRed
Graphics::TBitmap * smRed
Definition: GraphicUnit.h:901
TOnePrefDir::FindLinkingPrefDir
bool FindLinkingPrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
Finds a pref dir element that links to another element at given vector number and link number & posit...
Definition: TrackUnit.cpp:13191
TTrack::FlipArray
int FlipArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'flipping' via menu items 'Edit' & 'Flip'
Definition: TrackUnit.h:762
TRailGraphics::LCPlainMan
Graphics::TBitmap * LCPlainMan
Definition: GraphicUnit.h:745
TRailGraphics::bm139
Graphics::TBitmap * bm139
Definition: GraphicUnit.h:381
TRailGraphics::gl3
Graphics::TBitmap * gl3
Definition: GraphicUnit.h:646
TPrefDirElement::CheckCount
int CheckCount
internal check value used when building preferred directions
Definition: TrackUnit.h:206
TRailGraphics::bm20
Graphics::TBitmap * bm20
Definition: GraphicUnit.h:393
TRailGraphics::sm77striped
Graphics::TBitmap * sm77striped
Definition: GraphicUnit.h:862
TOneRoute::GetPreferredRouteStartElement
bool GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool AutoSigsFlag)
Set the starting conditions for a preferred direction or automatic signal route selection beginning o...
Definition: TrackUnit.cpp:14212
TAllRoutes::RebuildRailwayFlag
bool RebuildRailwayFlag
this is set whenever a route has to be cancelled forcibly in order to force a ClearandRebuildRailway ...
Definition: TrackUnit.h:1673
TUtilities::LoadFileInt
int LoadFileInt(std::ifstream &InFile)
loads an int value from the file
Definition: Utilities.cpp:162
TTrack::SignalAspectBuildMode
enum TTrack::@2 SignalAspectBuildMode
aspect mode for future signal additions
TTrackElement::ElementID
AnsiString ElementID
the element identifier based on position in the railway
Definition: TrackUnit.h:129
TRailGraphics::sm112
Graphics::TBitmap * sm112
Definition: GraphicUnit.h:782
TTrack::CheckMapAndInactiveTrack
void CheckMapAndInactiveTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:7701
TTrack::TActiveLevelCrossing::StartTime
TDateTime StartTime
stores the starting time for level crossing changing
Definition: TrackUnit.h:628
TRailGraphics::sm36
Graphics::TBitmap * sm36
Definition: GraphicUnit.h:823
TRailGraphics::sm136
Graphics::TBitmap * sm136
Definition: GraphicUnit.h:796
TRailGraphics::gl98
Graphics::TBitmap * gl98
Definition: GraphicUnit.h:730
TTrackElement::VLoc
int VLoc
The h & v locations in the railway (top lh corner of the first build screen = 0,0)
Definition: TrackUnit.h:146
TTrack::GetNonPointsOppositeLinkPos
int GetNonPointsOppositeLinkPos(int LinkPosIn)
Return the corresponding link position (track always occupies either links 0 & 1 or 2 & 3)
Definition: TrackUnit.h:883
TRailGraphics::sm100
Graphics::TBitmap * sm100
Definition: GraphicUnit.h:769
TOneRoute::TRouteFlash::RouteFlashVector
std::vector< TRouteFlashElement > RouteFlashVector
Definition: TrackUnit.h:1491
TRailGraphics::sm63
Graphics::TBitmap * sm63
Definition: GraphicUnit.h:853
TAllRoutes::TLockedRouteClass::LastTrackVectorPosition
unsigned int LastTrackVectorPosition
the TrackVector position of the last (i.e. most forward) element in the route
Definition: TrackUnit.h:1609
TRailGraphics::sm60
Graphics::TBitmap * sm60
Definition: GraphicUnit.h:850
TAllRoutes::NoRoute
@ NoRoute
Definition: TrackUnit.h:1619
TRailGraphics::bm42
Graphics::TBitmap * bm42
Definition: GraphicUnit.h:437
TTrack::RepositionAndMapTrack
bool RepositionAndMapTrack(int Caller)
When track is being built it is entered into the TrackVector in the order in which it is built,...
Definition: TrackUnit.cpp:4696
TRailGraphics::gl108
Graphics::TBitmap * gl108
Definition: GraphicUnit.h:585
TTrack::AdjNamedElement
bool AdjNamedElement(int Caller, int HLoc, int VLoc, int SpeedTag, AnsiString &LocationName, int &FoundElement)
Used in SearchForAndUpdateLocationName to check for adjacent named elements to a given element at HLo...
Definition: TrackUnit.cpp:9035
TTrainController::RestartTime
TDateTime RestartTime
TTClockTime when operation pauses ( = timetable start time prior to operation) TTClockTime is calcula...
Definition: TrainUnit.h:702
TOneRoute::ConvertAndAddPreferredRouteSearchVector
void ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
Called after a preferred (i.e. preferred direction or automatic signals) route has been selected and ...
Definition: TrackUnit.cpp:15399
TOnePrefDir::ClearPrefDir
void ClearPrefDir()
Empty the existing vectors & map.
Definition: TrackUnit.h:1307
TRailGraphics::gl99
Graphics::TBitmap * gl99
Definition: GraphicUnit.h:731
TGraphicElement::OverlayLoaded
bool OverlayLoaded
Definition: TrackUnit.h:430
TOnePrefDir::RealignAfterTrackErase
void RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
After a track element is erased the preferred direction elements are likely to be affected....
Definition: TrackUnit.cpp:13514
TRailGraphics::sm4
Graphics::TBitmap * sm4
Definition: GraphicUnit.h:827
PrefDirCall
@ PrefDirCall
Definition: TrackUnit.h:1285
TOnePrefDir::BiDirectionalPrefDir
bool BiDirectionalPrefDir(int Caller, TPrefDir4MultiMapIterator PDPtr)
Determines whether the preferred direction pointed to has another pref dir in the opposite direction ...
Definition: TrackUnit.cpp:13289
TTrackElement::StationEntryStopLinkPos1
int StationEntryStopLinkPos1
Definition: TrackUnit.h:150
TRailGraphics::gl89unset
Graphics::TBitmap * gl89unset
Definition: GraphicUnit.h:717
Points
@ Points
Definition: TrackUnit.h:65
TRailGraphics::LCPlain
Graphics::TBitmap * LCPlain
Definition: GraphicUnit.h:738
TAllRoutes::FindRoutePairFromRoute2MultiMap
TRouteElementPair FindRoutePairFromRoute2MultiMap(int Caller, int HLoc, int VLoc, int ELink, TRoute2MultiMapIterator &Route2MultiMapIterator)
Examines Route2MultiMap and returns a TRouteElementPair if one is found with the passed values of H,...
Definition: TrackUnit.cpp:18133
TRailGraphics::sm80
Graphics::TBitmap * sm80
Definition: GraphicUnit.h:868
TTrack::IsElementDefaultLength
bool IsElementDefaultLength(int Caller, TTrackElement &TrackElement, bool FirstTrack, bool &LengthDifferent, bool &SpeedDifferent)
Definition: TrackUnit.cpp:9884
TTrack::PopulateLCVector
void PopulateLCVector(int Caller)
Add all LCs to LCVector - note that this contains all LC elements whether linked to others or not.
Definition: TrackUnit.cpp:11173
TRailGraphics::bm33
Graphics::TBitmap * bm33
Definition: GraphicUnit.h:410
TRailGraphics::gl119
Graphics::TBitmap * gl119
Definition: GraphicUnit.h:597
TRailGraphics::sm47
Graphics::TBitmap * sm47
Definition: GraphicUnit.h:835
TRailGraphics::bm75grounddblred
Graphics::TBitmap * bm75grounddblred
Definition: GraphicUnit.h:499
TTrack::WriteOperatingTrackAndTextToImage
void WriteOperatingTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveOperatingImage1Click to add all track & text to the image file in their ope...
Definition: TrackUnit.cpp:4163
Trail
@ Trail
Definition: TrackUnit.h:75
TOneRoute::SetRouteSearchVectorGraphics
void SetRouteSearchVectorGraphics(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
Set values for EXGraphicPtr and EntryDirectionGraphicPtr for all elements in SearchVector so that the...
Definition: TrackUnit.cpp:17412
TTrack::ChangeLocationNameMultiMapEntry
void ChangeLocationNameMultiMapEntry(int Caller, AnsiString NewName, TLocationNameMultiMapIterator SNIterator)
Changes the LocationName in the name multimap to NewName at the location pointed to by the TLocationN...
Definition: TrackUnit.cpp:9268
TOneRoute::SetRearwardsSignalsReturnFalseForTrain
bool SetRearwardsSignalsReturnFalseForTrain(int Caller, int &Attribute, int PrefDirVectorStartPosition) const
Called by TAllRoutes::SetAllRearwardsSignals to set rearwards signals from a specified starting posit...
Definition: TrackUnit.cpp:16997
TRailGraphics::sm107
Graphics::TBitmap * sm107
Definition: GraphicUnit.h:776
TGraphicElement::LoadOverlayGraphic
void LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
Load the temporary overlay graphic.
Definition: TrackUnit.cpp:1850
TRailGraphics::bm75dblyellow
Graphics::TBitmap * bm75dblyellow
Definition: GraphicUnit.h:498
FailLockedRoute
@ FailLockedRoute
Definition: TrainUnit.h:40
TRailGraphics::sm32
Graphics::TBitmap * sm32
Definition: GraphicUnit.h:819
TOneRoute::SetRouteSignals
void SetRouteSignals(int Caller) const
Called when setting a route to set all points appropriately. Also called when a new train is added at...
Definition: TrackUnit.cpp:16815
TRailGraphics::sm44
Graphics::TBitmap * sm44
Definition: GraphicUnit.h:832
TRailGraphics::gl44
Graphics::TBitmap * gl44
Definition: GraphicUnit.h:662
TRailGraphics::bm36
Graphics::TBitmap * bm36
Definition: GraphicUnit.h:419
TRailGraphics::LCTopHor
Graphics::TBitmap * LCTopHor
Definition: GraphicUnit.h:740
Continuation
@ Continuation
Definition: TrackUnit.h:65
TRailGraphics::DirectionPrefDirGraphicsPtr
Graphics::TBitmap * DirectionPrefDirGraphicsPtr[10]
preferred direction marker arrows
Definition: GraphicUnit.h:1040
TUserGraphicItem::Height
int Height
Definition: DisplayUnit.h:35
TTrack::GetFilletGraphic
Graphics::TBitmap * GetFilletGraphic(int Caller, TTrackElement TrackElement)
Return a pointer to the point fillet (the bit that appears to move when points are changed) for the p...
Definition: TrackUnit.cpp:7580
GraphicUnit.h
TTrack::RebuildTrackAndText
void RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
Called by TInterface::ClearandRebuildRailway to replot all the active and inactive track elements and...
Definition: TrackUnit.cpp:3739
TextUnit.h
TTrack::PlotPoints
void PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
Plot points on screen according to how they are set (Attribute value), or, with both fillets if BothF...
Definition: TrackUnit.cpp:6018
TDisplay::DisplayZoomOutOffsetV
static int DisplayZoomOutOffsetV
the verticalal offset of the zoomed-out display
Definition: DisplayUnit.h:87
TTrack::RightPlatAllowed
Set< int, 1, 146 > RightPlatAllowed
Definition: TrackUnit.h:586
TRailGraphics::bm12
Graphics::TBitmap * bm12
Definition: GraphicUnit.h:356
TTrack::DecrementValuesInInactiveTrackAndNameMaps
void DecrementValuesInInactiveTrackAndNameMaps(int Caller, unsigned int VecPos)
After an element has been erased from the InactiveTrackVector, all the later elements are moved down ...
Definition: TrackUnit.cpp:9315
TRailGraphics::sm8
Graphics::TBitmap * sm8
Definition: GraphicUnit.h:867
TRailGraphics::sm87
Graphics::TBitmap * sm87
Definition: GraphicUnit.h:875
AllRoutes
TAllRoutes * AllRoutes
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:54
TRailGraphics::sm94
Graphics::TBitmap * sm94
Definition: GraphicUnit.h:883
TOnePrefDir::ValidatePrefDir
bool ValidatePrefDir(int Caller)
Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default value...
Definition: TrackUnit.cpp:12146
TTrack::LinkHVArray
int LinkHVArray[10][2]
array used to determine relative horizontal & vertical track element positions for specific link valu...
Definition: TrackUnit.h:572
TRailGraphics::sm49
Graphics::TBitmap * sm49
Definition: GraphicUnit.h:837
TRailGraphics::sm1
Graphics::TBitmap * sm1
Definition: GraphicUnit.h:767
TRailGraphics::sm84
Graphics::TBitmap * sm84
Definition: GraphicUnit.h:872
TGraphicElement::ScreenGraphicLoaded
bool ScreenGraphicLoaded
Definition: TrackUnit.h:430
TOneRoute::SearchForPreferredRoute
bool SearchForPreferredRoute(int Caller, TPrefDirElement PrefDirElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID, TOnePrefDir *EveryPrefDir, bool ConsecSignals, int EndSelectPosition, bool AutoSigsFlag)
Called by GetNextPreferredRouteElement to carry out the search for a valid route, and also called rec...
Definition: TrackUnit.cpp:14860
TTrack::TopPlatAllowed
Set< int, 1, 146 > TopPlatAllowed
Definition: TrackUnit.h:586
TRailGraphics::LinkPrefDirGraphicsPtr
Graphics::TBitmap * LinkPrefDirGraphicsPtr[30]
preferred direction graphic overlay
Definition: GraphicUnit.h:1029
TTrack::CheckTrackElementsInFile
bool CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream &VecFile)
True if TrackElements in the file are all valid.
Definition: TrackUnit.cpp:3356
TGraphicElement::Height
int Height
dimensions in pixels
Definition: TrackUnit.h:434
TRailGraphics::sm98
Graphics::TBitmap * sm98
Definition: GraphicUnit.h:888
TOneRoute::StartSelectionRouteID
IDInt StartSelectionRouteID
needed for session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1508
TFixedTrackPiece::SpeedTag
int SpeedTag
The element identification number - corresponds to the relevant SpeedButton->Tag.
Definition: TrackUnit.h:87
TRailGraphics::bm68green
Graphics::TBitmap * bm68green
Definition: GraphicUnit.h:456
TRailGraphics::gl79
Graphics::TBitmap * gl79
Definition: GraphicUnit.h:703
TTrain::Stopped
bool Stopped()
True if the train has stopped for any reason.
Definition: TrainUnit.h:669
TTrack::SigTableGroundSignal
TSigElement SigTableGroundSignal[40]
new at version 0.6 for ground signals
Definition: TrackUnit.h:723
TAllRoutes::LockedRouteLastXLinkPos
int LockedRouteLastXLinkPos
Definition: TrackUnit.h:1667
TRailGraphics::sm113
Graphics::TBitmap * sm113
Definition: GraphicUnit.h:926
TRailGraphics::bm135
Graphics::TBitmap * bm135
Definition: GraphicUnit.h:369
TPrefDirElement::GetELink
int GetELink() const
Returns ELink.
Definition: TrackUnit.h:263
TRailGraphics::LCBothVerMan
Graphics::TBitmap * LCBothVerMan
Definition: GraphicUnit.h:743
TUtilities::CheckFileDouble
bool CheckFileDouble(std::ifstream &InFile)
checks that the value is a double, returns true for success
Definition: Utilities.cpp:331
TRailGraphics::sm61
Graphics::TBitmap * sm61
Definition: GraphicUnit.h:851
TAllRoutes::DiagonalFouledByRouteOrTrain
bool DiagonalFouledByRouteOrTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
The track geometry allows diagonals to cross without occupying the same track element,...
Definition: TrackUnit.cpp:19233
TRailGraphics::bm73grounddblwhite
Graphics::TBitmap * bm73grounddblwhite
Definition: GraphicUnit.h:487
TOnePrefDir::CheckPrefDir4MultiMap
void CheckPrefDir4MultiMap(int Caller)
Diagnostic validity check.
Definition: TrackUnit.cpp:13086
TRailGraphics::BridgeSigRouteGraphicsPtr
Graphics::TBitmap * BridgeSigRouteGraphicsPtr[12]
route graphic for preferred routes overlay
Definition: GraphicUnit.h:1018
TRailGraphics::bm73dblyellow
Graphics::TBitmap * bm73dblyellow
Definition: GraphicUnit.h:485
TRailGraphics::sm111
Graphics::TBitmap * sm111
Definition: GraphicUnit.h:781
TOneRoute::TRouteFlashElement::OriginalGraphic
Graphics::TBitmap * OriginalGraphic
Definition: TrackUnit.h:1482
TRailGraphics::BridgeRouteAutoSigsGraphicsPtr
Graphics::TBitmap * BridgeRouteAutoSigsGraphicsPtr[12]
route graphic for automatic signal routes overlay
Definition: GraphicUnit.h:1022
TDisplay::DisplayZoomOutOffsetH
static int DisplayZoomOutOffsetH
the horizontal offset of the zoomed-out display
Definition: DisplayUnit.h:85
Display
TDisplay * Display
The object pointer for the on-screen display, object created in InterfaceUnit.
Definition: DisplayUnit.cpp:53
TRailGraphics::bm106
Graphics::TBitmap * bm106
Definition: GraphicUnit.h:350
TRailGraphics::bm56
Graphics::TBitmap * bm56
Definition: GraphicUnit.h:449
TTrack::RotRightArray
int RotRightArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating right' via menu items 'Edit' & 'Rotate right'
Definition: TrackUnit.h:768
TRailGraphics::gl146Striped
Graphics::TBitmap * gl146Striped
Definition: GraphicUnit.h:630
TTrack::GetVLocMin
int GetVLocMin()
Definition: TrackUnit.h:877
TTrack::ResetPoints
void ResetPoints(int Caller)
Called on exit from operation to reset all points to non-diverging or to left fork (Attribute = 0)
Definition: TrackUnit.cpp:4681
TRailGraphics::sm96striped
Graphics::TBitmap * sm96striped
Definition: GraphicUnit.h:886
TAllRoutes::StoreOneRoute
void StoreOneRoute(int Caller, TOneRoute *Route)
A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector.
Definition: TrackUnit.cpp:18031
TAllRoutes::AllRoutesSize
unsigned int AllRoutesSize() const
Returns the number of routes in the railway.
Definition: TrackUnit.h:1700
TTrack::DuplicatedLocationName
bool DuplicatedLocationName(int Caller, bool GiveMessage)
examines LocationNameMultiMap and returns true if there are two or more locations with the same name ...
Definition: TrackUnit.cpp:8625
TRailGraphics::gl87
Graphics::TBitmap * gl87
Definition: GraphicUnit.h:713
TTrack::THVPairsLinkedMap
std::map< THVPair, bool > THVPairsLinkedMap
added at v2.6.1 for use in PopulateHVPairsLinkedMapAndNoDuplicates
Definition: TrackUnit.h:691
TDisplay::Ellipse
void Ellipse(int Caller, int HPos, int VPos, TColor Col)
Plot an ellipse at the defined position and with the defined colour.
Definition: DisplayUnit.cpp:123
TRailGraphics::gl113
Graphics::TBitmap * gl113
Definition: GraphicUnit.h:591
TTrack::LCVector
TLCVector LCVector
vector of level crossing InactiveTrackVector positions
Definition: TrackUnit.h:788
TRailGraphics::gl49
Graphics::TBitmap * gl49
Definition: GraphicUnit.h:667
TUtilities::CheckFileBool
bool CheckFileBool(std::ifstream &InFile)
checks that the value is a bool returns true for success
Definition: Utilities.cpp:209
TTrack::OtherTrainOnTrack
bool OtherTrainOnTrack(int Caller, int NextPos, int NextEntryPos, int OwnTrainID)
True if another train on NextEntryPos track of element at NextPos, whether bridge or not,...
Definition: TrackUnit.cpp:10960
TRailGraphics::sm38
Graphics::TBitmap * sm38
Definition: GraphicUnit.h:825
TTrack::TActiveTrackElementNameMapEntry
std::pair< AnsiString, int > TActiveTrackElementNameMapEntry
Definition: TrackUnit.h:702
TOnePrefDir::SearchLimitHighV
int SearchLimitHighV
Definition: TrackUnit.h:1339
TAllRoutes::SaveRoutes
void SaveRoutes(int Caller, std::ofstream &OutFile)
Save railway route information to a session file or an error file.
Definition: TrackUnit.cpp:19070
TTrack::Tag77Array
int Tag77Array[25][3]
Definition: TrackUnit.h:576
TGraphicElement::PlotOverlay
void PlotOverlay(int Caller, TDisplay *Disp)
Plot the overlay graphic on screen.
Definition: TrackUnit.cpp:1860
TTrack::ResetSignals
void ResetSignals(int Caller)
Called on exit from operation to reset all signals to red (Attribute = 0)
Definition: TrackUnit.cpp:4666
Connection
@ Connection
Definition: TrackUnit.h:75
TTrack::LoadBarriersDownVector
void LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
Load all BarriersDownVector values from SessionFile.
Definition: TrackUnit.cpp:3716
TRailGraphics::bm13
Graphics::TBitmap * bm13
Definition: GraphicUnit.h:359
TAllRoutes::RouteTruncateFlag
bool RouteTruncateFlag
used to flag the fact that a route is being truncated on order to change the behaviour of signal aspe...
Definition: TrackUnit.h:1675
TTrack::MarkOneLength
void MarkOneLength(int Caller, TTrackElement TE, bool FirstTrack, TDisplay *Disp)
Mark on screen a track element according to its length and speed limit if either of these differ from...
Definition: TrackUnit.cpp:9547
TRailGraphics::bmStraightNSSignalBlank
Graphics::TBitmap * bmStraightNSSignalBlank
Definition: GraphicUnit.h:1009
TRailGraphics::LCTopHorMan
Graphics::TBitmap * LCTopHorMan
Definition: GraphicUnit.h:747
TRailGraphics::bm75green
Graphics::TBitmap * bm75green
Definition: GraphicUnit.h:501
TOneRoute::ConvertAndAddNonPreferredRouteSearchVector
void ConvertAndAddNonPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID)
Called after a non-preferred (i.e. unrestricted) route has been selected and has finished flashing,...
Definition: TrackUnit.cpp:16628
TOnePrefDir::ConvertPrefDirSearchVector
void ConvertPrefDirSearchVector(int Caller)
Called after a successful search to add the elements from the search vector to the pref dir vector.
Definition: TrackUnit.cpp:11964
TRailGraphics::gl91set
Graphics::TBitmap * gl91set
Definition: GraphicUnit.h:721
TRailGraphics::sm37
Graphics::TBitmap * sm37
Definition: GraphicUnit.h:824
TTrack::ElementInLNPendingList
bool ElementInLNPendingList(int Caller, int MapPos)
Definition: TrackUnit.cpp:8551
TRailGraphics::sm86
Graphics::TBitmap * sm86
Definition: GraphicUnit.h:874
TRailGraphics::LinkGraphicsPtr
Graphics::TBitmap * LinkGraphicsPtr[30]
basic single track graphic for use in plotting the original graphic during route flashing
Definition: GraphicUnit.h:1027
TAllRoutes::CheckMapAndRoutes
void CheckMapAndRoutes(int Caller)
Diagnostic function - checks equivalence for each route between entries in PrefDirVector and those in...
Definition: TrackUnit.cpp:18342
TAllRoutes::GetRouteElementDataFromRoute2MultiMap
TRouteElementPair GetRouteElementDataFromRoute2MultiMap(int Caller, int HLoc, int VLoc, TRouteElementPair &SecondPair)
Retrieve up to two TRouteElementPair entries from Route2MultiMap at H & V, the first as a function re...
Definition: TrackUnit.cpp:18298
TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway.
Definition: TrackUnit.cpp:7062
TPrefDirElement::GetPrefDirGraphicPtr
Graphics::TBitmap * GetPrefDirGraphicPtr()
picks up the EXGraphicPtr for preferred directions
Definition: TrackUnit.cpp:561
TTrack::PlatformOnSignalSide
bool PlatformOnSignalSide(int Caller, int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap *&SignalPlatformGraphic)
Check whether there is a platform present at HLoc & VLoc at the same side as the signal represented b...
Definition: TrackUnit.cpp:10831
TRailGraphics::gl80
Graphics::TBitmap * gl80
Definition: GraphicUnit.h:706
TRailGraphics::sm79
Graphics::TBitmap * sm79
Definition: GraphicUnit.h:865
TTrack::SigTable
TSigElement SigTable[40]
original table of signals for four aspect
Definition: TrackUnit.h:717
TOnePrefDir::TPrefDirVectorConstIterator
std::vector< TPrefDirElement >::const_iterator TPrefDirVectorConstIterator
Definition: TrackUnit.h:1366
TRailGraphics::smName
Graphics::TBitmap * smName
Definition: GraphicUnit.h:898
TRailGraphics::bm73grounddblred
Graphics::TBitmap * bm73grounddblred
Definition: GraphicUnit.h:486
TTrack::InactiveTrackElementPresentAtHV
bool InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if an inactive track element present.
Definition: TrackUnit.cpp:5806
TRailGraphics::sm7
Graphics::TBitmap * sm7
Definition: GraphicUnit.h:858
TRailGraphics::gl91unset
Graphics::TBitmap * gl91unset
Definition: GraphicUnit.h:722
TRailGraphics::bm50
Graphics::TBitmap * bm50
Definition: GraphicUnit.h:445
TDisplay::PlotSignalBlank
void PlotSignalBlank(int Caller, int HLoc, int VLoc, int SpeedTag, bool RHSFlag)
Definition: DisplayUnit.cpp:261
TGraphicElement::OriginalLoaded
bool OriginalLoaded
Definition: TrackUnit.h:430
TTrack::OverrideAndHideSignalBridgeMessage
bool OverrideAndHideSignalBridgeMessage
if false signals facing bridges are not permitted, but can be set to true using CTRL ALT 5
Definition: TrackUnit.h:752
TTrack::SetStationEntryStopLinkPosses
void SetStationEntryStopLinkPosses(int Caller)
Called when trying to link track and when a name changed when track already linked.
Definition: TrackUnit.cpp:10007
TTrack::HLocMin
int HLocMin
Definition: TrackUnit.h:568
TTrack::SigTableThreeAspect
TSigElement SigTableThreeAspect[40]
new at version 0.6 for three aspect
Definition: TrackUnit.h:719
TTrack::CopyFlag
bool CopyFlag
true only when copying a selection, used to prevent location names being copied
Definition: TrackUnit.h:730
TAllRoutes::GetModifiableRouteAt
TOneRoute & GetModifiableRouteAt(int Caller, int At)
Returns a modifiable reference to the route at AllRoutesVector position 'At', after performing range ...
Definition: TrackUnit.cpp:17568
TTrack::LinkTrack
bool LinkTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool FinalCall)
Attempt to link the track and return true if successful, if unsuccessful return error flag and positi...
Definition: TrackUnit.cpp:4806
TRailGraphics::sm16
Graphics::TBitmap * sm16
Definition: GraphicUnit.h:802
TTrack::ErrorInTrackBeforeSetGaps
bool ErrorInTrackBeforeSetGaps(int Caller, int &HLoc, int &VLoc)
Check for track errors prior to gap setting - disused as incorporated a time-consuming double brute f...
Definition: TrackUnit.cpp:2752
TRailGraphics::gl69
Graphics::TBitmap * gl69
Definition: GraphicUnit.h:689
TTrack::CheckMapAndTrack
void CheckMapAndTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:7661
TRailGraphics::bm140
Graphics::TBitmap * bm140
Definition: GraphicUnit.h:387
TTrack::LoadGraphics
void LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
new at v2.4.0, load user graphics
Definition: TrackUnit.cpp:3118
TRailGraphics::bm137
Graphics::TBitmap * bm137
Definition: GraphicUnit.h:375
TRailGraphics::sm64
Graphics::TBitmap * sm64
Definition: GraphicUnit.h:854
TTrackElement::LocationName
AnsiString LocationName
location name not used for timetabling, only for identification: platforms, non-station named locatio...
Definition: TrackUnit.h:131
TRailGraphics::sm90
Graphics::TBitmap * sm90
Definition: GraphicUnit.h:879
TRailGraphics::bm136
Graphics::TBitmap * bm136
Definition: GraphicUnit.h:372
TOneRoute::SetRoutePoints
void SetRoutePoints(int Caller) const
Called when setting a route to set all points appropriately.
Definition: TrackUnit.cpp:16786
TTrack::TActiveLevelCrossing::HLoc
int HLoc
HLoc value for found level crossing element.
Definition: TrackUnit.h:624
TDisplay::DisplayOffsetH
static int DisplayOffsetH
the horizontal offset of the displayed screen
Definition: DisplayUnit.h:77
TOnePrefDir::PresetAutoRouteElementValid
bool PresetAutoRouteElementValid(int Caller, TPrefDirElement ElementIn, int EntryPos)
Checks ElementIn and returns true only if a single prefdir set at that H&V, with EntryPos giving entr...
Definition: TrackUnit.cpp:13778
TPrefDirElement::EntryExitNumber
bool EntryExitNumber()
determines and loads EXNumber (see above)
Definition: TrackUnit.cpp:313
TRailGraphics::bm101
Graphics::TBitmap * bm101
Definition: GraphicUnit.h:349
TTrack::SkipLocationNameMultiMapCheck
bool SkipLocationNameMultiMapCheck
changed from PastingWithAttributes in v2.4.0 as all pastes are now with attributes - needed to suppre...
Definition: TrackUnit.h:750
TRailGraphics::gl125
Graphics::TBitmap * gl125
Definition: GraphicUnit.h:604
TTrack::TLocationNameMultiMapRange
std::pair< TLocationNameMultiMapIterator, TLocationNameMultiMapIterator > TLocationNameMultiMapRange
Definition: TrackUnit.h:688
TRailGraphics::gl145Striped
Graphics::TBitmap * gl145Striped
Definition: GraphicUnit.h:628
TRailGraphics::bm27
Graphics::TBitmap * bm27
Definition: GraphicUnit.h:394
TRailGraphics::bm73yellow
Graphics::TBitmap * bm73yellow
Definition: GraphicUnit.h:489
InRouteTrue
@ InRouteTrue
Definition: TrackUnit.h:1279
TTrack::TUserGraphicMapEntry
std::pair< AnsiString, TPicture * > TUserGraphicMapEntry
an entry for TUserGraphicMap
Definition: TrackUnit.h:649
TRailGraphics::bm69yellow
Graphics::TBitmap * bm69yellow
Definition: GraphicUnit.h:463
TTrack::TGapMapIterator
TGapMap::iterator TGapMapIterator
the first gap HLoc/VLoc pair, contains one entry for each pair of matched gaps
Definition: TrackUnit.h:659
TRailGraphics::bmTransparentBgnd
Graphics::TBitmap * bmTransparentBgnd
Definition: GraphicUnit.h:914
TRailGraphics::gl23
Graphics::TBitmap * gl23
Definition: GraphicUnit.h:639
TOnePrefDir::GetNextPrefDirElement
bool GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
Used when continuing a chain of preferred directions or element lengths. Tries to find a set of linke...
Definition: TrackUnit.cpp:11524
TRailGraphics::bm68grounddblwhite
Graphics::TBitmap * bm68grounddblwhite
Definition: GraphicUnit.h:455
TGraphicElement::OverlayPlotted
bool OverlayPlotted
Definition: TrackUnit.h:430
TRailGraphics::bm93unset
Graphics::TBitmap * bm93unset
Definition: GraphicUnit.h:515
TRailGraphics::sm122
Graphics::TBitmap * sm122
Definition: GraphicUnit.h:933
TFixedTrackPiece::TrackType
TTrackType TrackType
the type of track element
Definition: TrackUnit.h:99
TOneRoute::TRouteFlashElement
A single flashing element of a route that flashes during setting.
Definition: TrackUnit.h:1478
TPrefDirElement
Basic preferred direction or route element - track element with additional members.
Definition: TrackUnit.h:195
TTrack::PopulateHVPairsLinkedMapAndNoDuplicates
bool PopulateHVPairsLinkedMapAndNoDuplicates(int Caller, TLocationNameMultiMapRange LNMMRg)
Used in checking for duplicate location names after Bill78 (discord name) developed the ....
Definition: TrackUnit.cpp:8674
TRailGraphics::sm26
Graphics::TBitmap * sm26
Definition: GraphicUnit.h:812
TGraphicElement::~TGraphicElement
~TGraphicElement()
Destructor.
Definition: TrackUnit.cpp:1758
TTrack::SearchForAndUpdateLocationName
void SearchForAndUpdateLocationName(int Caller, int HLoc, int VLoc, int SpeedTag)
Checks all locations that are adjacent to the one entered for linked named location elements.
Definition: TrackUnit.cpp:8856
TRailGraphics::gl24
Graphics::TBitmap * gl24
Definition: GraphicUnit.h:640
TRailGraphics::gl109
Graphics::TBitmap * gl109
Definition: GraphicUnit.h:586
TTrack::TSigElement
Used as basic elements in a table of signals - see SigTable below.
Definition: TrackUnit.h:707
TOnePrefDir::GetOnePrefDirPosition
int GetOnePrefDirPosition(int Caller, int HLoc, int VLoc)
Although there may be up to four entries at one H & V position this function gets just one....
Definition: TrackUnit.cpp:13485
TAllRoutes::GetFixedRouteAtIDNumber
const TOneRoute & GetFixedRouteAtIDNumber(int Caller, IDInt RouteID) const
Returns a constant reference to the route with ID number RouteID. If no route is found with that ID a...
Definition: TrackUnit.cpp:19038
TTrackElement::Attribute
int Attribute
special variable used only for points, signals & level crossings, ignored otherwise; points 0=set to ...
Definition: TrackUnit.h:140
TTrack::TBarrierState
TBarrierState
< state of barriers, values for level crossings either changing state or with barriers up or down
Definition: TrackUnit.h:606
TOnePrefDir::SearchLimitLowH
int SearchLimitLowH
Definition: TrackUnit.h:1336
TRailGraphics::SetUpAllDerivitiveGraphics
void SetUpAllDerivitiveGraphics(TColor TransparentColour)
Definition: GraphicUnit.cpp:4259
TTrack::LocationNameMultiMap
TLocationNameMultiMap LocationNameMultiMap
multimap of location names (see type for more information above)
Definition: TrackUnit.h:794
TTrack::NoNamedLocationElements
bool NoNamedLocationElements(int Caller)
True if there are no NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4557
TTrack::PlotSmallFlashingLinkedLevelCrossings
void PlotSmallFlashingLinkedLevelCrossings(int Caller, int HLoc, int VLoc, Graphics::TBitmap *GraphicPtr, TDisplay *Disp)
Plots either a LC or a blank element to flash manual LCs in zoomout mode.
Definition: TrackUnit.cpp:7524
TTrack::EraseTrackElement
void EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
Erases all active and inactive track elements at HLocInput & VLocInput from the vectors,...
Definition: TrackUnit.cpp:1955
TRailGraphics::bmRedEllipse
Graphics::TBitmap * bmRedEllipse
Definition: GraphicUnit.h:526
TRailGraphics::LinkRouteAutoSigsGraphicsPtr
Graphics::TBitmap * LinkRouteAutoSigsGraphicsPtr[30]
auto signal route graphic overlay
Definition: GraphicUnit.h:1035
TTrack::SetBarriersDownLCToManual
void SetBarriersDownLCToManual(int Caller, int HLoc, int VLoc)
Set TypeOfRoute value to 2 to indicate barriers manually closed.
Definition: TrackUnit.cpp:6326
TRailGraphics::bmDiagonalSignalBlank
Graphics::TBitmap * bmDiagonalSignalBlank
Definition: GraphicUnit.h:1006
TRailGraphics::gl83
Graphics::TBitmap * gl83
Definition: GraphicUnit.h:709
FootCrossing
@ FootCrossing
Definition: TrackUnit.h:65
TRailGraphics::sm50
Graphics::TBitmap * sm50
Definition: GraphicUnit.h:839
TRailGraphics::gl25
Graphics::TBitmap * gl25
Definition: GraphicUnit.h:641
TTrack::IsLCAtHV
bool IsLCAtHV(int Caller, int HLoc, int VLoc)
True if a level crossing is found at H & V.
Definition: TrackUnit.cpp:7319
Platform
@ Platform
Definition: TrackUnit.h:65
TOnePrefDir::SearchVector
TPrefDirVector SearchVector
pref dir vectors, first is the main vector, second used to store search elements temporarily
Definition: TrackUnit.h:1368
TPrefDirElement::EXGraphicPtr
Graphics::TBitmap * EXGraphicPtr
Definition: TrackUnit.h:208
TTrack::TGapMapEntry
std::pair< THVPair, THVPair > TGapMapEntry
Definition: TrackUnit.h:661
TRailGraphics::sm95
Graphics::TBitmap * sm95
Definition: GraphicUnit.h:884
TTrack::LevelCrossingBarrierDownFlashDuration
float LevelCrossingBarrierDownFlashDuration
duration of the flash period when level crossing opening
Definition: TrackUnit.h:756
TTrainController::TTClockTime
TDateTime TTClockTime
the time indicated by the timetable clock
Definition: TrainUnit.h:698
TTrack::LocationsNotNamed
bool LocationsNotNamed(int Caller)
True if there are unnamed NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4582
TTrack::RotLeftArray
int RotLeftArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating left' via menu items 'Edit' & 'Rotate left'
Definition: TrackUnit.h:770
TAllRoutes::TLockedRouteClass::LockStartTime
TDateTime LockStartTime
the timetable time at which the route is locked, to start the 2 minute clock
Definition: TrackUnit.h:1613
TRailGraphics::DirectionNonSigRouteGraphicsPtr
Graphics::TBitmap * DirectionNonSigRouteGraphicsPtr[10]
unrestricted route marker arrows
Definition: GraphicUnit.h:1042
TRailGraphics::sm11
Graphics::TBitmap * sm11
Definition: GraphicUnit.h:779
TRailGraphics::sm125
Graphics::TBitmap * sm125
Definition: GraphicUnit.h:936
TTrack::InactiveMapCheck
bool InactiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
Used to check the validity of footcrossing links.
Definition: TrackUnit.cpp:8074
TRailGraphics::gl6
Graphics::TBitmap * gl6
Definition: GraphicUnit.h:679
TOnePrefDir
The basic preferred direction class, consisting of any number of elements with preferred directions s...
Definition: TrackUnit.h:1292
TRailGraphics::sm23
Graphics::TBitmap * sm23
Definition: GraphicUnit.h:809
TRailGraphics::sm55
Graphics::TBitmap * sm55
Definition: GraphicUnit.h:844
TTrack::NonFootCrossingNamedLocationExists
bool NonFootCrossingNamedLocationExists(int Caller)
True if there is a platform, NamedNonStationLocation or Concourse present in the railway.
Definition: TrackUnit.cpp:9464
TRailGraphics::BridgePrefDirGraphicsPtr
Graphics::TBitmap * BridgePrefDirGraphicsPtr[12]
preferred direction graphic overlay
Definition: GraphicUnit.h:1016
TRailGraphics::sm10
Graphics::TBitmap * sm10
Definition: GraphicUnit.h:768
TTrack::FindClosestLinkPosition
int FindClosestLinkPosition(int Caller, int StartTVPosition, int EndTVPosition)
Return the link array position for the element at StartTVPosition that gives the closest link to the ...
Definition: TrackUnit.cpp:11067
TGraphicElement::SetScreenHVSource
void SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
Set HPos, VPos & SourceRect member values from the supplied positions.
Definition: TrackUnit.cpp:1765
TRailGraphics::sm41
Graphics::TBitmap * sm41
Definition: GraphicUnit.h:829
TUtilities::CallLog
std::deque< AnsiString > CallLog
call stack store, saved to the errorlog for diagnostic purposes
Definition: Utilities.h:55
TRailGraphics::gl22
Graphics::TBitmap * gl22
Definition: GraphicUnit.h:638
TOneRoute::TRouteFlashElement::HLoc
int HLoc
Definition: TrackUnit.h:1480
TRailGraphics::bm100
Graphics::TBitmap * bm100
Definition: GraphicUnit.h:348
TOneRoute::GetNextNonPreferredRouteElement
bool GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks between the route start element and the one at HLoc & VLoc....
Definition: TrackUnit.cpp:15820
TTrack::LCInSearchVector
bool LCInSearchVector(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector)
checks for a route being set across an LC to prevent barriers raising
Definition: TrackUnit.cpp:7507
TTrack::UserGraphicVector
TUserGraphicVector UserGraphicVector
Definition: TrackUnit.h:796
TTrackElement::Length23
int Length23
Definition: TrackUnit.h:148
TRailGraphics::sm134
Graphics::TBitmap * sm134
Definition: GraphicUnit.h:794
TUtilities::LoadFileBool
bool LoadFileBool(std::ifstream &InFile)
loads a bool value from the file
Definition: Utilities.cpp:145
TRailGraphics::gl71
Graphics::TBitmap * gl71
Definition: GraphicUnit.h:692
TOneRoute::TRouteFlashElement::OverlayGraphic
Graphics::TBitmap * OverlayGraphic
displayed alternately during flashing
Definition: TrackUnit.h:1482
TTrack::TActiveLevelCrossing
Definition: TrackUnit.h:611
TTrack::AnyLinkedBarrierDownVectorManual
bool AnyLinkedBarrierDownVectorManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
Checks BarrierDownVector and returns true if there is one that is linked to the LC at H & V positions...
Definition: TrackUnit.cpp:6343
TRailGraphics::gl92set
Graphics::TBitmap * gl92set
Definition: GraphicUnit.h:723
TTrack::SaveSessionBarriersDownVector
void SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
Save all vector values to the session file.
Definition: TrackUnit.cpp:3616
TRailGraphics::sm102
Graphics::TBitmap * sm102
Definition: GraphicUnit.h:771
TRailGraphics::gl4
Graphics::TBitmap * gl4
Definition: GraphicUnit.h:657
TDisplay::PlotAndAddUserGraphic
void PlotAndAddUserGraphic(int Caller, TUserGraphicItem UserGraphicItem)
Plot user graphic.
Definition: DisplayUnit.cpp:99
TTrack::DefaultTrackSpeedLimit
int DefaultTrackSpeedLimit
speed limit of each track element before being changed within the program (can be changed in config....
Definition: TrackUnit.h:760
TDisplay::PlotSmallOutput
void PlotSmallOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot small (4x4) graphic PlotItem on the zoomed-out display at HPos & Vpos.
Definition: DisplayUnit.cpp:113
TTrack::Tag96Array
int Tag96Array[28][3]
Definition: TrackUnit.h:579
TRailGraphics::sm15
Graphics::TBitmap * sm15
Definition: GraphicUnit.h:801
TTrack::LCChangeFlag
bool LCChangeFlag
true when LCs changing
Definition: TrackUnit.h:736
TTrack::SelectVectorAt
TTrackElement & SelectVectorAt(int Caller, int At)
A range-checked version of SelectVector.at(At)
Definition: TrackUnit.cpp:10993
TRailGraphics::sm13
Graphics::TBitmap * sm13
Definition: GraphicUnit.h:788
TRailGraphics::sm91
Graphics::TBitmap * sm91
Definition: GraphicUnit.h:880
TRailGraphics::sm59
Graphics::TBitmap * sm59
Definition: GraphicUnit.h:848
TTrackElement::SpeedLimit23
int SpeedLimit23
Element lengths and speed limits, ...01 is for the track with link positions [0] and [1],...
Definition: TrackUnit.h:148
THVPair
std::pair< int, int > THVPair
HLoc/VLoc position pair.
Definition: TrackUnit.h:40
TTrack::TLNPendingListIterator
TLNPendingList::iterator TLNPendingListIterator
naming of linked named location elements
Definition: TrackUnit.h:675
TRailGraphics::sm114
Graphics::TBitmap * sm114
Definition: GraphicUnit.h:927
TPrefDirElement::LogPrefDir
AnsiString LogPrefDir() const
Sends a list of PrefDirElement values to Utilities->CallLog file for debugging purposes.
Definition: TrackUnit.cpp:299
TRailGraphics::gl82
Graphics::TBitmap * gl82
Definition: GraphicUnit.h:708
TTrack::TActiveLevelCrossing::ChangeDuration
float ChangeDuration
duration of the level crossing changing period
Definition: TrackUnit.h:620
TRailGraphics::gl95set
Graphics::TBitmap * gl95set
Definition: GraphicUnit.h:727
TDisplay::DisplayOffsetVHome
static int DisplayOffsetVHome
the vertical offset of the 'Home' display
Definition: DisplayUnit.h:83
TPrefDirElement::operator==
bool operator==(TPrefDirElement RHElement)
equivalence operator
Definition: TrackUnit.cpp:1074
TrainUnit.h
TRailGraphics::bm34
Graphics::TBitmap * bm34
Definition: GraphicUnit.h:413
TRailGraphics::gl104
Graphics::TBitmap * gl104
Definition: GraphicUnit.h:581
TFixedTrackPiece::Link
int Link[4]
Track connection link values, max. of 4, unused = -1, top lh diag.=1, top=2, top rh diag....
Definition: TrackUnit.h:89
TOneRoute::SearchForNonPreferredRoute
bool SearchForNonPreferredRoute(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID)
Called by GetNextNonPreferredRouteElement to carry out the search for linked track,...
Definition: TrackUnit.cpp:16194
TTrack::TLNDone2MultiMapEntry
std::pair< THVPair, int > TLNDone2MultiMapEntry
can be up to 2 entries (platforms) at a single location
Definition: TrackUnit.h:682
TTrack::TrackMap
TTrackMap TrackMap
map of track (see type for more information above)
Definition: TrackUnit.h:799
RouteCall
@ RouteCall
Definition: TrackUnit.h:1285
TRailGraphics::bm141
Graphics::TBitmap * bm141
Definition: GraphicUnit.h:388
TOnePrefDir::GetFixedSearchElementAt
const TPrefDirElement & GetFixedSearchElementAt(int Caller, int At) const
Return a non-modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:11458
TRailGraphics::sm76striped
Graphics::TBitmap * sm76striped
Definition: GraphicUnit.h:860
TTextHandler::TextErase
bool TextErase(int Caller, int HPosition, int VPosition, AnsiString TextToErase)
look for a text item in the vicinity of HPosInput & VPosInput & if TextToErase is null then erase any...
Definition: TextUnit.cpp:265
TRailGraphics::gl127
Graphics::TBitmap * gl127
Definition: GraphicUnit.h:606
TRailGraphics::bm75yellow
Graphics::TBitmap * bm75yellow
Definition: GraphicUnit.h:502
NotSet
@ NotSet
Definition: TrackUnit.h:75
TTrack::TInactiveTrack2MultiMapIterator
TInactiveTrack2MultiMap::iterator TInactiveTrack2MultiMapIterator
iterator for TInactiveTrack2MultiMap
Definition: TrackUnit.h:665
TAllRoutes::SetTrailingSignalsOnContinuationRoute
void SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber)
This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in...
Definition: TrackUnit.cpp:18614
TDisplay::DisplayZoomOutOffsetHHome
static int DisplayZoomOutOffsetHHome
the horizontal offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:89
TMapComp::operator()
bool operator()(const THVPair &lower, const THVPair &higher) const
HLoc VLoc.
Definition: TrackUnit.cpp:261
TRailGraphics::bm16
Graphics::TBitmap * bm16
Definition: GraphicUnit.h:391
TRailGraphics::gl128
Graphics::TBitmap * gl128
Definition: GraphicUnit.h:607
TRailGraphics::gl116
Graphics::TBitmap * gl116
Definition: GraphicUnit.h:594
TTrack::FindHighestLowestAndLeftmostNamedElements
bool FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
Used in locating the screen name position for a named location, return true if find an inactive eleme...
Definition: TrackUnit.cpp:11022
TTrack::TrackClear
void TrackClear(int Caller)
Empty the track and inactive track vectors, the corresponding track maps, and LocationNameMultiMap.
Definition: TrackUnit.cpp:10283
TTrack::TIMPair
std::pair< unsigned int, unsigned int > TIMPair
TrackElement pair type used for inactive elements, values are vector positions.
Definition: TrackUnit.h:670
TTextHandler::TextVectorSize
unsigned int TextVectorSize(int Caller)
return the number of items in TextVector
Definition: TextUnit.cpp:533
TPrefDirElement::ELink
int ELink
Definition: TrackUnit.h:198
TRailGraphics::sm130striped
Graphics::TBitmap * sm130striped
Definition: GraphicUnit.h:790
TRailGraphics::sm118
Graphics::TBitmap * sm118
Definition: GraphicUnit.h:929
TTrack::SetLinkedLevelCrossingBarrierAttributes
void SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
Set linked LC attributes; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to trai...
Definition: TrackUnit.cpp:6244
TTrackElement::GroundSignal
@ GroundSignal
Definition: TrackUnit.h:157
LevelCrossing
@ LevelCrossing
Definition: TrackUnit.h:66
TRailGraphics::sm126
Graphics::TBitmap * sm126
Definition: GraphicUnit.h:937
TTrack::ActiveTrackElementNameMapCompiledFlag
bool ActiveTrackElementNameMapCompiledFlag
indicates that the ActiveTrackElementNameMap has been compiled
Definition: TrackUnit.h:728
TOnePrefDir::GetModifiableSearchElementAt
TPrefDirElement & GetModifiableSearchElementAt(int Caller, int At)
Return a modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:11470
TOnePrefDir::TotalSearchCount
int TotalSearchCount
counts search elements, used to abort searches (prefdirs or routes) if reaches too high a value
Definition: TrackUnit.h:1341
Track
TTrack * Track
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:53
TRailGraphics::bm18
Graphics::TBitmap * bm18
Definition: GraphicUnit.h:392
TTrackElement::Conn
int Conn[4]
Connecting element position in TrackVector, set to -1 if no connecting link or if track not linked.
Definition: TrackUnit.h:142
TTrack::~TTrack
~TTrack()
Destructor.
Definition: TrackUnit.cpp:1530
TRailGraphics::sm62
Graphics::TBitmap * sm62
Definition: GraphicUnit.h:852
TRailGraphics::LCBothVer
Graphics::TBitmap * LCBothVer
Definition: GraphicUnit.h:736
TRailGraphics::sm35
Graphics::TBitmap * sm35
Definition: GraphicUnit.h:822
RailGraphics
TRailGraphics * RailGraphics
the object pointer, object created in InterfaceUnit
Definition: GraphicUnit.cpp:50
TRailGraphics::gl81
Graphics::TBitmap * gl81
Definition: GraphicUnit.h:707
TTrack::HLocMax
int HLocMax
Definition: TrackUnit.h:568
TRailGraphics::gl146
Graphics::TBitmap * gl146
Definition: GraphicUnit.h:629
TTrack::PlotSmallRedGap
void PlotSmallRedGap(int Caller)
Plot on screen in zoomed-out mode and in gap setting mode a small red square corresponding to the gap...
Definition: TrackUnit.cpp:10274
Bridge
@ Bridge
Definition: TrackUnit.h:65
TTrack::DefaultTrackLength
int DefaultTrackLength
length of each track element before being changed within the program (can be changed in config....
Definition: TrackUnit.h:758
TRailGraphics::sm78
Graphics::TBitmap * sm78
Definition: GraphicUnit.h:863
TRailGraphics::bm43
Graphics::TBitmap * bm43
Definition: GraphicUnit.h:440
InRouteFalse
@ InRouteFalse
Definition: TrackUnit.h:1279
TRailGraphics::sm25
Graphics::TBitmap * sm25
Definition: GraphicUnit.h:811
TRailGraphics::bmName
Graphics::TBitmap * bmName
Definition: GraphicUnit.h:524
Gap
@ Gap
Definition: TrackUnit.h:75
Buffers
@ Buffers
Definition: TrackUnit.h:65
TOneRoute::SetRemainingSearchVectorValues
void SetRemainingSearchVectorValues(int Caller)
Called when setting unrestricted routes to set the route element values appropriately after a success...
Definition: TrackUnit.cpp:16544
TRailGraphics::gl79Striped
Graphics::TBitmap * gl79Striped
Definition: GraphicUnit.h:704
TUtilities::ScreenElementHeight
int ScreenElementHeight
height of display screen in elements
Definition: Utilities.h:50
CrossConn
@ CrossConn
Definition: TrackUnit.h:75
TOnePrefDir::GetPrefDirStartElement
bool GetPrefDirStartElement(int Caller, int HLoc, int VLoc)
Used when beginning a chain of preferred directions or element lengths. Enter with HLoc & VLoc set to...
Definition: TrackUnit.cpp:11482
TRailGraphics::bm71grounddblwhite
Graphics::TBitmap * bm71grounddblwhite
Definition: GraphicUnit.h:474
TTrack::GapsUnset
bool GapsUnset(int Caller)
True if there are gaps in the railway and any are unset.
Definition: TrackUnit.cpp:4494
TOnePrefDir::LastElementNumber
int LastElementNumber(int Caller) const
Return the vector position of the last element in the vector (i.e. one less than the vector size)
Definition: TrackUnit.cpp:11405
TRailGraphics::sm58
Graphics::TBitmap * sm58
Definition: GraphicUnit.h:847